Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/end2end_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ jobs:
success_key: e2e-success-evaluations
artifact_name: Playwright Report (Evaluations)
postgres: false
- name: Distribution
index_script: index_distribution.py
playwright_project: distribution
shard: "1/1"
success_marker: .e2e-success-distribution
success_key: e2e-success-distribution
artifact_name: Playwright Report (Distribution)
postgres: false
- name: General Postgres 1 of 2
index_script: index_general.py
playwright_project: general
Expand Down
8 changes: 8 additions & 0 deletions lightly_studio/e2e-tests/index_distribution.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
DATASET_NAME = "distribution_example_dataset"
RANDOM_SEED = 42

COMPARISON_TAG_REVIEWED = "distribution_reviewed"
COMPARISON_TAG_PRIORITY = "distribution_priority"
COMPARISON_TAG_EMPTY = "distribution_empty"

# Distinct, weighted class pools per type so each distribution has a clear shape.
CLASSIFICATION_CLASSES = ["daytime", "night", "dawn", "dusk", "indoor"]
CLASSIFICATION_WEIGHTS = [0.45, 0.25, 0.15, 0.1, 0.05]
Expand Down Expand Up @@ -114,6 +118,10 @@ def main() -> None:
samples = list(dataset)
rng = random.Random(RANDOM_SEED)

dataset.query()[:32].add_tag(COMPARISON_TAG_REVIEWED)
dataset.query()[16:48].add_tag(COMPARISON_TAG_PRIORITY)
dataset.query()[:0].add_tag(COMPARISON_TAG_EMPTY)

for sample in samples:
annotations: list[CreateAnnotation] = []

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { expect, test } from '../utils';
import { distributionComparison } from './fixtures';

test('compares overlapping and empty sample tags without reloading or filtering the grid', async ({
page,
samplesPage
}) => {
const firstId = await samplesPage.getTagIdByName(distributionComparison.firstTag);
const secondId = await samplesPage.getTagIdByName(distributionComparison.secondTag);
const emptyId = await samplesPage.getTagIdByName(distributionComparison.emptyTag);
expect(firstId).toBeTruthy();
expect(secondId).toBeTruthy();
expect(emptyId).toBeTruthy();

await page.getByTestId('side-panel-tabs-distribution').click();
await expect(page.getByTestId('dataset-distribution-panel')).toBeVisible();
const urlBeforeComparison = page.url();
let navigationCount = 0;
let imageListRequestCount = 0;
const recordNavigation = () => navigationCount++;
const recordImageListRequest = (request: { url: () => string }) => {
if (request.url().includes('/images/list')) imageListRequestCount++;
};
page.on('framenavigated', recordNavigation);
page.on('request', recordImageListRequest);

const waitForGroupedCounts = (tagCount: number) =>
page.waitForResponse((response) => {
if (!response.url().includes('/annotations/count-by-sample-tags')) return false;
const body = response.request().postDataJSON() as { sample_tag_ids?: string[] };
return response.status() === 200 && body.sample_tag_ids?.length === tagCount;
});
const selectTag = async (tagId: string, expectedCount: number) => {
const option = page.getByTestId(`dataset-distribution-tag-option-${tagId}`);
if (!(await option.isVisible())) {
await page.getByTestId('dataset-distribution-tag-select').click();
}
const responsePromise = waitForGroupedCounts(expectedCount);
await option.click();
return responsePromise;
};

await selectTag(firstId!, 1);
await selectTag(secondId!, 2);
const response = await selectTag(emptyId!, 3);
const requestBody = response.request().postDataJSON() as { sample_tag_ids: string[] };
expect(requestBody.sample_tag_ids).toEqual([firstId, secondId, emptyId]);
const groupedCounts = (await response.json()) as {
sample_tag_id: string;
counts: { count: number }[];
}[];
const emptyCounts = groupedCounts.find((item) => item.sample_tag_id === emptyId)?.counts;
expect(emptyCounts?.length).toBeGreaterThan(0);
expect(emptyCounts?.every((item) => item.count === 0)).toBe(true);

await expect(page.getByText(/3 sample tags/)).toBeVisible();
expect(page.url()).toBe(urlBeforeComparison);
expect(navigationCount).toBe(0);
expect(imageListRequestCount).toBe(0);
page.off('framenavigated', recordNavigation);
page.off('request', recordImageListRequest);
});
5 changes: 5 additions & 0 deletions lightly_studio_view/e2e/distribution/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const distributionComparison = {
firstTag: 'distribution_reviewed',
secondTag: 'distribution_priority',
emptyTag: 'distribution_empty'
} as const;
4 changes: 4 additions & 0 deletions lightly_studio_view/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ export default defineConfig({
{
name: 'evaluations',
testDir: './e2e/evaluations'
},
{
name: 'distribution',
testDir: './e2e/distribution'
}
],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@
<Command.Empty>No sample tag found.</Command.Empty>
<Command.Group>
{#each items as item (item.value)}
<Command.Item value={item.label} onSelect={() => toggle(item.value)}>
<Command.Item
value={item.label}
data-testid={`dataset-distribution-tag-option-${item.value}`}
onSelect={() => toggle(item.value)}
>
<Check
class={cn(!selectedIds.includes(item.value) && 'text-transparent')}
/>
Expand Down