diff --git a/e2e/projects.spec.ts b/e2e/projects.spec.ts index 20d41314..d4cab6c2 100644 --- a/e2e/projects.spec.ts +++ b/e2e/projects.spec.ts @@ -13,7 +13,7 @@ import { archiveProjectViaApi, updateOrganizationSettingViaApi, } from './utils/api'; -import { clearTableState, getTableRowNames } from './utils/table'; +import { clearTableState, getSeededRowOrder } from './utils/table'; async function goToProjectsOverview(page: Page) { await page.goto(PLAYWRIGHT_BASE_URL + '/projects'); @@ -654,14 +654,12 @@ test('test that projects without a client or estimate are ordered by name at the page, ctx, }) => { - // The seeding below has to cross two second boundaries, which eats into the default - // per-test budget. - test.slow(); - + // Seeded a second apart: created_at only has second precision and same-second rows + // fall back to a random UUID order. The spacing makes the API order of the clientless + // rows (created_at desc: ZZZ, AAA) deterministic and different from the alphabetical + // order the name tie-break should produce. await createProjectViaApi(ctx, { name: 'AAA Tiebreak Project' }); await page.waitForTimeout(1100); - await createProjectViaApi(ctx, { name: 'BBB Tiebreak Project' }); - await page.waitForTimeout(1100); await createProjectViaApi(ctx, { name: 'ZZZ Tiebreak Project' }); const clientAardvark = await createClientViaApi(ctx, { name: 'Aardvark Co' }); @@ -688,17 +686,11 @@ test('test that projects without a client or estimate are ordered by name at the const seeded = [ 'AAA Tiebreak Project', - 'BBB Tiebreak Project', 'MMM Tiebreak Project', 'NNN Tiebreak Project', 'ZZZ Tiebreak Project', ]; - const getOrder = async () => { - const rowNames = await getTableRowNames(table); - return rowNames - .map((rowName) => seeded.find((name) => rowName.includes(name))) - .filter((name): name is string => Boolean(name)); - }; + const getOrder = () => getSeededRowOrder(table, seeded); // -- Client: empty rows last in both directions, alphabetical among themselves -- const clientHeader = table.locator('.select-none', { hasText: 'Client' }).first(); @@ -709,7 +701,6 @@ test('test that projects without a client or estimate are ordered by name at the 'MMM Tiebreak Project', 'NNN Tiebreak Project', 'AAA Tiebreak Project', - 'BBB Tiebreak Project', 'ZZZ Tiebreak Project', ]); @@ -720,7 +711,6 @@ test('test that projects without a client or estimate are ordered by name at the 'NNN Tiebreak Project', 'MMM Tiebreak Project', 'AAA Tiebreak Project', - 'BBB Tiebreak Project', 'ZZZ Tiebreak Project', ]); @@ -733,7 +723,6 @@ test('test that projects without a client or estimate are ordered by name at the 'NNN Tiebreak Project', 'MMM Tiebreak Project', 'AAA Tiebreak Project', - 'BBB Tiebreak Project', 'ZZZ Tiebreak Project', ]); @@ -744,7 +733,6 @@ test('test that projects without a client or estimate are ordered by name at the 'MMM Tiebreak Project', 'NNN Tiebreak Project', 'AAA Tiebreak Project', - 'BBB Tiebreak Project', 'ZZZ Tiebreak Project', ]); }); diff --git a/e2e/utils/table.ts b/e2e/utils/table.ts index 6af1f8a9..4cb081df 100644 --- a/e2e/utils/table.ts +++ b/e2e/utils/table.ts @@ -15,6 +15,16 @@ export async function getTableRowNames(table: Locator): Promise { return names; } +/** + * The visual order of the given seeded names within the table, ignoring any other rows. + */ +export async function getSeededRowOrder(table: Locator, seeded: string[]): Promise { + const rowNames = await getTableRowNames(table); + return rowNames + .map((rowName) => seeded.find((name) => rowName.includes(name))) + .filter((name): name is string => Boolean(name)); +} + /** * Drop a table's persisted sort/filter state so a test starts from the defaults. */ diff --git a/resources/js/Components/Common/Client/ClientTableHeading.vue b/resources/js/Components/Common/Client/ClientTableHeading.vue index 21eb7295..8ca19b17 100644 --- a/resources/js/Components/Common/Client/ClientTableHeading.vue +++ b/resources/js/Components/Common/Client/ClientTableHeading.vue @@ -1,5 +1,4 @@