From 599187ac686b96aa1b3b8c0f9115ba5d23177bae Mon Sep 17 00:00:00 2001 From: Script Raccoon Date: Sat, 15 Aug 2026 19:29:05 +0200 Subject: [PATCH] improve end-to-end tests --- tests/categories.spec.ts | 104 ++++++++++---------- tests/category-comparison.spec.ts | 31 +++--- tests/category-implications.spec.ts | 2 +- tests/category-properties.spec.ts | 28 +++--- tests/category-search.spec.ts | 30 +++--- tests/content.spec.ts | 46 +++++---- tests/functor-implications.spec.ts | 2 +- tests/functor-properties.spec.ts | 27 +++-- tests/functor-search.spec.ts | 41 ++++---- tests/functors.spec.ts | 41 ++++---- tests/missing.spec.ts | 101 ++++++++++++++++--- tests/morphism-implications.spec.ts | 2 +- tests/morphism-properties.spec.ts | 36 ++++--- tests/morphism-search.spec.ts | 29 +++--- tests/morphisms.spec.ts | 37 +++---- tests/structure_selector.spec.ts | 70 ++++++------- tests/symmetric_monoidal_categories.spec.ts | 14 +-- 17 files changed, 358 insertions(+), 283 deletions(-) diff --git a/tests/categories.spec.ts b/tests/categories.spec.ts index 80ab16369..129179e8d 100644 --- a/tests/categories.spec.ts +++ b/tests/categories.spec.ts @@ -103,18 +103,18 @@ test('user can view category details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('objects: commutative rings')).toBeVisible() - await expect(page.getByText('morphisms: ring homomorphisms')).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('Objects: commutative rings') + await expect(body).toContainText('Morphisms: ring homomorphisms') await expect(page.getByRole('link', { name: 'nLab link' })).toBeVisible() - await expect(page.getByText('is cocomplete')).toBeVisible() - await expect(page.getByText('is locally finitely presentable')).toBeVisible() - await expect(page.getByText('is not additive')).toBeVisible() - await expect(page.getByText('is not balanced')).toBeVisible() - await expect(page.getByText('terminal object: zero ring')).toBeVisible() - await expect(page.getByText('coproducts: tensor products')).toBeVisible() - await expect( - page.getByText('regular epimorphisms: surjective morphisms') - ).toBeVisible() + await expect(body).toContainText('is cocomplete') + await expect(body).toContainText('is locally finitely presentable') + await expect(body).toContainText('is not additive') + await expect(body).toContainText('is not balanced') + await expect(body).toContainText('terminal object: zero ring') + await expect(body).toContainText('coproducts: tensor products') + await expect(body).toContainText('regular epimorphisms: surjective morphisms') }) test('user sees no unknown properties for the category of sets', async ({ page }) => { @@ -137,15 +137,13 @@ test('user may see unknown properties', async ({ page }) => { }) ).toBeVisible() - const unknown_properties_section = page - .locator('section', { - hasText: 'Unknown properties' - }) - .first() + const unknown_properties_section = page.locator('section', { + hasText: 'Unknown properties' + }) - const unknown_property_link = unknown_properties_section.locator('li').first() + const link = unknown_properties_section.locator('li').first() - await expect(unknown_property_link).toBeVisible() + await expect(link).toBeVisible() }) test('user may see undecidable properties', async ({ page }) => { @@ -158,11 +156,9 @@ test('user may see undecidable properties', async ({ page }) => { }) ).toBeVisible() - const undecidable_properties_section = page - .locator('section', { - hasText: 'Undecidable properties' - }) - .first() + const undecidable_properties_section = page.locator('section', { + hasText: 'Undecidable properties' + }) const link = undecidable_properties_section.getByRole('link', { name: 'accessible', @@ -184,11 +180,9 @@ test('user may see properties that cannot be determined in a family of categorie }) ).toBeVisible() - const undecidable_properties_section = page - .locator('section', { - hasText: 'Undecidable properties' - }) - .first() + const undecidable_properties_section = page.locator('section', { + hasText: 'Undecidable properties' + }) const link = undecidable_properties_section.getByRole('link', { name: 'finite', @@ -202,6 +196,7 @@ test('user can navigate to a related category', async ({ page }) => { await page.goto('/category/FinSet', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Related categories:' }) .getByRole('link', { name: 'category of sets', exact: true @@ -230,11 +225,8 @@ test('user can navigate to the dual category if it exists in the database', asyn }) ).toBeVisible() - const item = page.locator('li', { - hasText: 'Dual category' - }) - - await item + await page + .locator('li', { hasText: 'Dual category' }) .getByRole('link', { name: 'dual of the category of sets', exact: true @@ -255,6 +247,7 @@ test('user can navigate to a child category', async ({ page }) => { await page.goto('/category/BG', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Children:' }) .getByRole('link', { name: 'delooping of a non-trivial finite group', exact: true @@ -275,11 +268,11 @@ test('user can navigate to a parent category', async ({ page }) => { await page.goto('/category/Ring', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Parent:' }) .getByRole('link', { name: 'category of algebras', exact: true }) - .first() .click() await expect( @@ -295,7 +288,7 @@ test('user can navigate to a parent category', async ({ page }) => { test('user can open and close a proof for a property of a category', async ({ page }) => { await page.goto('/category/Grp', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is mono-regular') }) + const claim = page.locator('li', { hasText: 'is mono-regular' }) await expect(claim).toBeVisible() @@ -331,7 +324,7 @@ test('user can open a proof for a deduced satisfied property of category', async }) => { await page.goto('/category/Ring', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('has an extremal generator') }) + const claim = page.locator('li', { hasText: 'has an extremal generator' }) await expect(claim).toBeVisible() @@ -339,11 +332,9 @@ test('user can open a proof for a deduced satisfied property of category', async const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText( - 'Since it is one-sorted finitary algebraic, it has an extremal generator' - ) - ).toBeVisible() + await expect(popup).toContainText( + 'Since it is one-sorted finitary algebraic, it has an extremal generator' + ) }) test('user can open a proof for a deduced unsatisfied property of a category', async ({ @@ -351,7 +342,7 @@ test('user can open a proof for a deduced unsatisfied property of a category', a }) => { await page.goto('/category/Ab', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is not cartesian closed') }) + const claim = page.locator('li', { hasText: 'is not cartesian closed' }) await expect(claim).toBeVisible() @@ -359,9 +350,9 @@ test('user can open a proof for a deduced unsatisfied property of a category', a const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText('Assume for contradiction that it is cartesian closed.') - ).toBeVisible() + await expect(popup).toContainText( + 'Assume for contradiction that it is cartesian closed.' + ) }) test('user can open a proof for an inherited satisfied property of a category', async ({ @@ -369,7 +360,7 @@ test('user can open a proof for an inherited satisfied property of a category', }) => { await page.goto('/category/Ab', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is abelian') }) + const claim = page.locator('li', { hasText: 'is abelian' }) await expect(claim).toBeVisible() @@ -377,7 +368,7 @@ test('user can open a proof for an inherited satisfied property of a category', const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect(popup.getByText('This follows from the parent.')).toBeVisible() + await expect(popup).toContainText('This follows from the parent.') }) test('user can open a proof for an inherited unsatisfied property of a category', async ({ @@ -385,7 +376,7 @@ test('user can open a proof for an inherited unsatisfied property of a category' }) => { await page.goto('/category/BG_f', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is not thin') }) + const claim = page.locator('li', { hasText: 'is not thin' }) await expect(claim).toBeVisible() @@ -393,7 +384,7 @@ test('user can open a proof for an inherited unsatisfied property of a category' const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect(popup.getByText('This follows from the parent.')).toBeVisible() + await expect(popup).toContainText('This follows from the parent.') }) test('user sees functors associated with the given category', async ({ page }) => { @@ -414,7 +405,7 @@ test('user sees functors associated with the given category', async ({ page }) = ).toBeVisible() }) -test('user sees morphisms stored for the given category', async ({ page }) => { +test('user sees morphisms associated with the given category', async ({ page }) => { await page.goto('/category/Grp', { waitUntil: 'networkidle' }) await expect( @@ -431,3 +422,16 @@ test('user sees morphisms stored for the given category', async ({ page }) => { }) ).toBeVisible() }) + +test('user sees symmetric monoidal categories for the given category', async ({ + page +}) => { + await page.goto('/category/Top', { waitUntil: 'networkidle' }) + + await expect( + page.getByRole('link', { + name: 'cartesian symmetric monoidal category of topological spaces', + exact: true + }) + ).toBeVisible() +}) diff --git a/tests/category-comparison.spec.ts b/tests/category-comparison.spec.ts index 297571fcf..f910c3321 100644 --- a/tests/category-comparison.spec.ts +++ b/tests/category-comparison.spec.ts @@ -79,27 +79,26 @@ test('user can view comparison table', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('category of rings')).toBeVisible() - await expect(page.getByText('category of commutative rings')).toBeVisible() + const body = page.locator('body') + await expect(body).toContainText('category of rings') + await expect(body).toContainText('category of commutative rings') const table = page.getByRole('table') await expect(table).toBeVisible() - const table_except = { - abelian: ['no', 'no'], - generator: ['yes', 'yes'], - cocomplete: ['yes', 'yes'], - coextensive: ['no', 'yes'] - } + const table_excerpt = [ + ['abelian', 'no', 'no'], + ['generator', 'yes', 'yes'], + ['cocomplete', 'yes', 'yes'], + ['coextensive', 'no', 'yes'] + ] - for (const [prop, values] of Object.entries(table_except)) { - const row = table - .locator('tbody tr', { - has: page.getByRole('link', { name: prop, exact: true }) - }) - .first() + for (const [prop, value_1, value_2] of table_excerpt) { + const row = table.locator('tbody tr', { + has: page.getByRole('link', { name: prop, exact: true }) + }) await expect(row).toBeVisible() - await expect(row.locator('td').nth(1)).toHaveAttribute('aria-label', values[0]) - await expect(row.locator('td').nth(2)).toHaveAttribute('aria-label', values[1]) + await expect(row.locator('td').nth(1)).toHaveAttribute('aria-label', value_1) + await expect(row.locator('td').nth(2)).toHaveAttribute('aria-label', value_2) } }) diff --git a/tests/category-implications.spec.ts b/tests/category-implications.spec.ts index 64b26fd90..533460995 100644 --- a/tests/category-implications.spec.ts +++ b/tests/category-implications.spec.ts @@ -62,7 +62,7 @@ test('user can see the details of an implication', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('Proof: This holds by definition')).toBeVisible() + await expect(page.locator('body')).toContainText('Proof: This holds by definition') }) test('user can open the list of deduced implications', async ({ page }) => { diff --git a/tests/category-properties.spec.ts b/tests/category-properties.spec.ts index a7d28815f..44f715298 100644 --- a/tests/category-properties.spec.ts +++ b/tests/category-properties.spec.ts @@ -49,14 +49,18 @@ test('user can view category property details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('A category is finitely accessible if')).toBeVisible() + await expect(page.locator('body')).toContainText( + 'A category is finitely accessible if' + ) - await expect( - page.getByRole('link', { + const related_link = page + .locator('li', { hasText: 'Related properties:' }) + .getByRole('link', { name: 'accessible', exact: true }) - ).toBeVisible() + + await expect(related_link).toBeVisible() const examples = page .getByRole('heading', { @@ -111,11 +115,8 @@ test('user can navigate to the dual property', async ({ page }) => { }) ).toBeVisible() - const item = page.locator('li', { - hasText: 'Dual property' - }) - - await item + await page + .locator('li', { hasText: 'Dual property:' }) .getByRole('link', { name: 'coequalizers', exact: true @@ -136,11 +137,10 @@ test('user sees no unknown categories for the property of being additive', async page }) => { await page.goto('/category-property/additive') - await expect( - page.getByText( - 'There are 0 categories for which the database has no information on whether they satisfy this property' - ) - ).toBeVisible() + + await expect(page.locator('body')).toContainText( + 'There are 0 categories for which the database has no information on whether they satisfy this property' + ) }) test("user can navigate to properties tagged with 'colimits' from the property list page", async ({ diff --git a/tests/category-search.spec.ts b/tests/category-search.spec.ts index d12522594..8dd91df45 100644 --- a/tests/category-search.spec.ts +++ b/tests/category-search.spec.ts @@ -28,40 +28,40 @@ test('user can navigate to the search page', async ({ page }) => { test('user can enter properties', async ({ page }) => { await page.goto('/category-search') - const satisfied_input_field = page.getByRole('textbox', { + const satisfied_textbox = page.getByRole('textbox', { name: 'Satisfied property', exact: true }) for (const p of ['finitely complete', 'finitely cocomplete']) { - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') - await satisfied_input_field.fill(p) - await satisfied_input_field.focus() + await satisfied_textbox.fill(p) + await satisfied_textbox.focus() await page.waitForTimeout(500) - await satisfied_input_field.press('Enter') + await satisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: p, exact: true })).toBeVisible() - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') } - const unsatisfied_input_field = page.getByRole('textbox', { + const unsatisfied_textbox = page.getByRole('textbox', { name: 'Unsatisfied property', exact: true }) for (const q of ['cocomplete', 'abelian']) { - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') - await unsatisfied_input_field.fill(q) - await unsatisfied_input_field.focus() + await unsatisfied_textbox.fill(q) + await unsatisfied_textbox.focus() await page.waitForTimeout(500) - await unsatisfied_input_field.press('Enter') + await unsatisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: q, exact: true })).toBeVisible() - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') } await page @@ -203,7 +203,7 @@ test('contradictions are detected', async ({ page }) => { '/category-search/results?satisfied=equalizers~products&unsatisfied=pullbacks' ) - await expect(page.getByText('the requirements are inconsistent')).toBeVisible() - - await expect(page.getByText('equalizers ∧ products ⟹ complete')).toBeVisible() + const body = page.locator('body') + await expect(body).toContainText('the requirements are inconsistent') + await expect(body).toContainText('equalizers ∧ products ⟹ complete') }) diff --git a/tests/content.spec.ts b/tests/content.spec.ts index 17b43cbdc..5f6859f1e 100644 --- a/tests/content.spec.ts +++ b/tests/content.spec.ts @@ -19,9 +19,11 @@ test('user can navigate to the foundations page', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('Grothendieck universes').first()).toBeVisible() - await expect(page.getByText('collections').first()).toBeVisible() - await expect(page.getByText('functor category').first()).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('Grothendieck universes') + await expect(body).toContainText('collections') + await expect(body).toContainText('functor category') }) test('user can navigate to the contributions page', async ({ page }) => { @@ -43,12 +45,14 @@ test('user can navigate to the contributions page', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('GitHub repository').first()).toBeVisible() - await expect(page.getByText('suggestion form').first()).toBeVisible() - await expect(page.getByText('pull request').first()).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('GitHub repository') + await expect(body).toContainText('suggestion form') + await expect(body).toContainText('pull request') }) -test('user can access the list of content pages', async ({ page }) => { +test('user can access a content page from the list page', async ({ page }) => { await page.goto('/content') await expect( @@ -67,25 +71,29 @@ test('user can access the list of content pages', async ({ page }) => { name: 'Cocongruences on groups' }) ).toBeVisible() + + const body = page.locator('body') + + await expect(body).toContainText('good pushouts of monomorphisms') + await expect(body).toContainText('Choose a system of representatives') }) -test('user can view proofs on a content page', async ({ page }) => { +test('user can view referencing categories on a content page', async ({ page }) => { await page.goto('/content/cocongruences_of_groups') - await expect( - page.getByRole('heading', { - name: 'Cocongruences on groups' - }) - ).toBeVisible() - - await expect(page.getByText('good pushouts of monomorphisms').first()).toBeVisible() + await expect(page.locator('body')).toContainText( + 'This page is referenced by the following categories.' + ) - await expect( - page.getByText('Choose a system of representatives').first() - ).toBeVisible() + const context = page + .getByRole('heading', { + name: 'Context', + exact: true + }) + .locator('xpath=following-sibling::ul') await expect( - page.getByRole('link', { + context.getByRole('link', { name: 'category of groups', exact: true }) diff --git a/tests/functor-implications.spec.ts b/tests/functor-implications.spec.ts index b0a433313..4c006c3f8 100644 --- a/tests/functor-implications.spec.ts +++ b/tests/functor-implications.spec.ts @@ -62,7 +62,7 @@ test('user can see the details of an implication', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText(/Proof:.+follows that/)).toBeVisible() + await expect(page.locator('body')).toContainText(/Proof:.+follows that/) }) test('user can open the list of deduced implications', async ({ page }) => { diff --git a/tests/functor-properties.spec.ts b/tests/functor-properties.spec.ts index 10292f885..a74adf9f7 100644 --- a/tests/functor-properties.spec.ts +++ b/tests/functor-properties.spec.ts @@ -49,16 +49,16 @@ test('user can view functor property details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('is faithful when')).toBeVisible() + await expect(page.locator('body')).toContainText('is faithful when') - await expect( - page - .getByRole('link', { - name: 'fully faithful', - exact: true - }) - .first() - ).toBeVisible() + const related_link = page + .locator('li', { hasText: 'Related properties' }) + .getByRole('link', { + name: 'fully faithful', + exact: true + }) + + expect(related_link).toBeVisible() const examples = page .getByRole('heading', { @@ -113,11 +113,10 @@ test('user can navigate to the dual property', async ({ page }) => { }) ).toBeVisible() - const item = page.locator('li', { - hasText: 'Dual property' - }) - - await item + await page + .locator('li', { + hasText: 'Dual property:' + }) .getByRole('link', { name: 'right exact', exact: true diff --git a/tests/functor-search.spec.ts b/tests/functor-search.spec.ts index 58dca0a0b..d4e2043cd 100644 --- a/tests/functor-search.spec.ts +++ b/tests/functor-search.spec.ts @@ -28,40 +28,40 @@ test('user can navigate to the search page', async ({ page }) => { test('user can enter properties', async ({ page }) => { await page.goto('/functor-search') - const satisfied_input_field = page.getByRole('textbox', { + const satisfied_textbox = page.getByRole('textbox', { name: 'Satisfied property', exact: true }) for (const p of ['preserves monomorphisms', 'preserves epimorphisms']) { - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') - await satisfied_input_field.fill(p) - await satisfied_input_field.focus() + await satisfied_textbox.fill(p) + await satisfied_textbox.focus() await page.waitForTimeout(500) - await satisfied_input_field.press('Enter') + await satisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: p, exact: true })).toBeVisible() - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') } - const unsatisfied_input_field = page.getByRole('textbox', { + const unsatisfied_textbox = page.getByRole('textbox', { name: 'Unsatisfied property', exact: true }) for (const q of ['left exact', 'right exact']) { - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') - await unsatisfied_input_field.fill(q) - await unsatisfied_input_field.focus() + await unsatisfied_textbox.fill(q) + await unsatisfied_textbox.focus() await page.waitForTimeout(500) - await unsatisfied_input_field.press('Enter') + await unsatisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: q, exact: true })).toBeVisible() - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') } await page @@ -189,15 +189,12 @@ test('contradictions are detected', async ({ page }) => { '/functor-search/results?satisfied=cocontinuous~continuous&unsatisfied=preserves_terminal_objects' ) - await expect(page.getByText('the requirements are inconsistent')).toBeVisible() + const body = page.locator('body') - await expect(page.getByText('continuous ⟹ preserves products')).toBeVisible() - - await expect( - page.getByText('preserves products ⟹ preserves finite products') - ).toBeVisible() - - await expect( - page.getByText('preserves finite products ⟹ preserves terminal objects') - ).toBeVisible() + await expect(body).toContainText('the requirements are inconsistent') + await expect(body).toContainText('continuous ⟹ preserves products') + await expect(body).toContainText('preserves products ⟹ preserves finite products') + await expect(body).toContainText( + 'preserves finite products ⟹ preserves terminal objects' + ) }) diff --git a/tests/functors.spec.ts b/tests/functors.spec.ts index 508d481f6..ee70244ea 100644 --- a/tests/functors.spec.ts +++ b/tests/functors.spec.ts @@ -64,7 +64,7 @@ test("user can navigate to functors tagged with 'topology' from the functor list ).toBeVisible() }) -test("user can navigate to functors tagged with 'algebra' from the category detail page", async ({ +test("user can navigate to functors tagged with 'algebra' from the functor detail page", async ({ page }) => { await page.goto('/functor/abelianization', { waitUntil: 'networkidle' }) @@ -101,12 +101,14 @@ test('user can view functor details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('group of homotopy classes of loops')).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('group of homotopy classes of loops') await expect(page.getByRole('link', { name: 'nLab link' })).toBeVisible() - await expect(page.getByText('preserves products')).toBeVisible() - await expect(page.getByText('is essentially surjective')).toBeVisible() - await expect(page.getByText('is not faithful')).toBeVisible() - await expect(page.getByText('does not preserve binary coproducts')).toBeVisible() + await expect(body).toContainText('preserves products') + await expect(body).toContainText('is essentially surjective') + await expect(body).toContainText('is not faithful') + await expect(body).toContainText('does not preserve binary coproducts') }) test('user sees no unknown properties for a forgetful functor', async ({ page }) => { @@ -128,11 +130,9 @@ test('user may see undecidable properties', async ({ page }) => { }) ).toBeVisible() - const undecidable_properties_section = page - .locator('section', { - hasText: 'Undecidable properties' - }) - .first() + const undecidable_properties_section = page.locator('section', { + hasText: 'Undecidable properties' + }) const link = undecidable_properties_section.getByRole('link', { name: 'essentially injective', @@ -146,6 +146,7 @@ test('user can navigate to a related functor', async ({ page }) => { await page.goto('/functor/forget_ring', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Related functors:' }) .getByRole('link', { name: 'forgetful functor for groups', exact: true @@ -166,6 +167,7 @@ test('user can navigate to the domain category', async ({ page }) => { await page.goto('/functor/forget_ring', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Domain:' }) .getByRole('link', { name: 'category of rings', exact: true @@ -186,6 +188,7 @@ test('user can navigate to the codomain category', async ({ page }) => { await page.goto('/functor/group_units', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Codomain:' }) .getByRole('link', { name: 'category of groups', exact: true @@ -206,6 +209,7 @@ test('user can navigate to the left adjoint functor', async ({ page }) => { await page.goto('/functor/group_units', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Left adjoint:' }) .getByRole('link', { name: 'forgetful functor from groups to monoids', exact: true @@ -226,6 +230,7 @@ test('user can navigate to the right adjoint functor', async ({ page }) => { await page.goto('/functor/forget_topology', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Right adjoint:' }) .getByRole('link', { name: 'indiscrete topology functor', exact: true @@ -245,7 +250,7 @@ test('user can navigate to the right adjoint functor', async ({ page }) => { test('user can open and close a proof for a property of a functor', async ({ page }) => { await page.goto('/functor/forget_ring', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is monadic') }) + const claim = page.locator('li', { hasText: 'is monadic' }) await expect(claim).toBeVisible() @@ -281,7 +286,7 @@ test('user can open a proof for a deduced satisfied property of functor', async }) => { await page.goto('/functor/free_group', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is cocontinuous') }) + const claim = page.locator('li', { hasText: 'is cocontinuous' }) await expect(claim).toBeVisible() @@ -289,9 +294,7 @@ test('user can open a proof for a deduced satisfied property of functor', async const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText('Since it is a left adjoint, it is cocontinuous') - ).toBeVisible() + await expect(popup).toContainText('Since it is a left adjoint, it is cocontinuous') }) test('user can open a proof for a deduced unsatisfied property of a functor', async ({ @@ -299,7 +302,7 @@ test('user can open a proof for a deduced unsatisfied property of a functor', as }) => { await page.goto('/functor/pi_1', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is not continuous') }) + const claim = page.locator('li', { hasText: 'is not continuous' }) await expect(claim).toBeVisible() @@ -307,7 +310,5 @@ test('user can open a proof for a deduced unsatisfied property of a functor', as const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText('Assume for contradiction that it is continuous.') - ).toBeVisible() + await expect(popup).toContainText('Assume for contradiction that it is continuous.') }) diff --git a/tests/missing.spec.ts b/tests/missing.spec.ts index 00d0e59d9..523d5071b 100644 --- a/tests/missing.spec.ts +++ b/tests/missing.spec.ts @@ -31,11 +31,12 @@ test('user can see categories with missing data', async ({ page }) => { }) ).toBeVisible() - const categories_section = page - .locator('section', { - hasText: 'Categories with unknown properties' + const categories_section = page.locator('section', { + has: page.getByRole('heading', { + name: 'Categories with unknown properties', + exact: true }) - .first() + }) await expect(categories_section).toBeVisible() @@ -49,7 +50,7 @@ test('user can see categories with missing data', async ({ page }) => { }) // this can be adjusted if at some point not all functors are understood -test('user can see no functors with missing data', async ({ page }) => { +test('user cannot see any functors with missing data', async ({ page }) => { await page.goto('/missing', { waitUntil: 'networkidle' }) await expect( @@ -60,14 +61,19 @@ test('user can see no functors with missing data', async ({ page }) => { ).toBeVisible() const functors_section = page.locator('section', { - hasText: 'Functors with unknown properties' + has: page.getByRole('heading', { + name: 'Functors with unknown properties', + exact: true + }) }) + await expect(functors_section).toBeVisible() + await expect(functors_section.getByRole('link')).toHaveCount(0) }) // this can be adjusted if at some point not all morphisms are understood -test('user can see no morphisms with missing data', async ({ page }) => { +test('user cannot see any morphisms with missing data', async ({ page }) => { await page.goto('/missing', { waitUntil: 'networkidle' }) await expect( @@ -78,22 +84,60 @@ test('user can see no morphisms with missing data', async ({ page }) => { ).toBeVisible() const morphisms_section = page.locator('section', { - hasText: 'Morphisms with unknown properties' + has: page.getByRole('heading', { + name: 'Morphisms with unknown properties', + exact: true + }) }) + await expect(morphisms_section).toBeVisible() + await expect(morphisms_section.getByRole('link')).toHaveCount(0) }) +// this can be adjusted if at some point not all +// symmetric monoidal categories are understood +test('user cannot see any symmetric monoidal categories with missing data', async ({ + page +}) => { + await page.goto('/missing', { waitUntil: 'networkidle' }) + + await expect( + page.getByRole('heading', { + name: 'Missing data', + exact: true + }) + ).toBeVisible() + + const symmetric_section = page.locator('section', { + has: page.getByRole('heading', { + name: 'Symmetric monoidal categories with unknown properties', + exact: true + }) + }) + + await expect(symmetric_section).toBeVisible() + + await expect(symmetric_section.getByRole('link')).toHaveCount(0) +}) + // this can be adjusted if at some point every category combination is witnessed test('user can see missing category combinations', async ({ page }) => { await page.goto('/missing', { waitUntil: 'networkidle' }) const combinations_section = page.locator('section', { - hasText: 'Missing category combinations' + has: page.getByRole('heading', { + name: 'Missing category combinations', + exact: true + }) }) await expect(combinations_section).toBeVisible() + await expect(combinations_section).not.toHaveText( + /Every consistent category property combination[\s\S]+is witnessed/ + ) + await combinations_section .locator('summary', { hasText: /Show all \d+ combinations/ }) .click() @@ -108,7 +152,10 @@ test('user cannot see any missing functor combinations', async ({ page }) => { await page.goto('/missing', { waitUntil: 'networkidle' }) const combinations_section = page.locator('section', { - hasText: 'Missing functor combinations' + has: page.getByRole('heading', { + name: 'Missing functor combinations', + exact: true + }) }) await expect(combinations_section).toBeVisible() @@ -123,7 +170,10 @@ test('user cannot see any missing morphism combinations', async ({ page }) => { await page.goto('/missing', { waitUntil: 'networkidle' }) const combinations_section = page.locator('section', { - hasText: 'Missing morphism combinations' + has: page.getByRole('heading', { + name: 'Missing morphism combinations', + exact: true + }) }) await expect(combinations_section).toBeVisible() @@ -132,3 +182,32 @@ test('user cannot see any missing morphism combinations', async ({ page }) => { /.+Every consistent morphism property combination[\s\S]+is witnessed/ ) }) + +// this can be adjusted if at some point every symmetric monoidal category +// combination is witnessed +test('user can see missing symmetric monoidal category combinations', async ({ + page +}) => { + await page.goto('/missing', { waitUntil: 'networkidle' }) + + const combinations_section = page.locator('section', { + has: page.getByRole('heading', { + name: 'Missing symmetric monoidal category combinations', + exact: true + }) + }) + + await expect(combinations_section).toBeVisible() + + await expect(combinations_section).not.toHaveText( + /Every consistent symmetric monoidal category property combination[\s\S]+is witnessed/ + ) + + await combinations_section + .locator('summary', { hasText: /Show all \d+ combinations/ }) + .click() + + await expect( + combinations_section.locator('li', { hasText: /[A-Za-z]+ ∧ ¬[A-Za-z]+/ }).first() + ).toBeVisible() +}) diff --git a/tests/morphism-implications.spec.ts b/tests/morphism-implications.spec.ts index 3aede8da1..fe4bd8eb6 100644 --- a/tests/morphism-implications.spec.ts +++ b/tests/morphism-implications.spec.ts @@ -64,7 +64,7 @@ test('user can see the details of an implication', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('Proof: Let')).toBeVisible() + await expect(page.locator('body')).toContainText('Proof: Let') }) test('user can open the list of deduced implications', async ({ page }) => { diff --git a/tests/morphism-properties.spec.ts b/tests/morphism-properties.spec.ts index 9cc700c6a..f84df3d05 100644 --- a/tests/morphism-properties.spec.ts +++ b/tests/morphism-properties.spec.ts @@ -49,16 +49,16 @@ test('user can view morphism property details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('is an effective epimorphism if')).toBeVisible() + await expect(page.locator('body')).toContainText('is an effective epimorphism if') - await expect( - page - .getByRole('link', { - name: 'regular epimorphism', - exact: true - }) - .first() - ).toBeVisible() + const related_link = page + .locator('li', { hasText: 'Related properties' }) + .getByRole('link', { + name: 'regular epimorphism', + exact: true + }) + + expect(related_link).toBeVisible() const examples = page .getByRole('heading', { @@ -113,11 +113,10 @@ test('user can navigate to the dual property', async ({ page }) => { }) ).toBeVisible() - const item = page.locator('li', { - hasText: 'Dual property' - }) - - await item + await page + .locator('li', { + hasText: 'Dual property:' + }) .getByRole('link', { name: 'strict monomorphism', exact: true @@ -138,11 +137,10 @@ test('user sees no unknown morphisms for the property of being an isomorphism', page }) => { await page.goto('/morphism-property/isomorphism') - await expect( - page.getByText( - 'There are 0 morphisms for which the database has no information on whether they satisfy this property' - ) - ).toBeVisible() + + await expect(page.locator('body')).toContainText( + 'There are 0 morphisms for which the database has no information on whether they satisfy this property' + ) }) test("user can navigate to properties tagged with 'types of epimorphism' from the property list page", async ({ diff --git a/tests/morphism-search.spec.ts b/tests/morphism-search.spec.ts index e1d406894..badf4e4c9 100644 --- a/tests/morphism-search.spec.ts +++ b/tests/morphism-search.spec.ts @@ -28,40 +28,40 @@ test('user can navigate to the search page', async ({ page }) => { test('user can enter properties', async ({ page }) => { await page.goto('/morphism-search') - const satisfied_input_field = page.getByRole('textbox', { + const satisfied_textbox = page.getByRole('textbox', { name: 'Satisfied property', exact: true }) for (const p of ['monomorphism', 'epimorphism']) { - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') - await satisfied_input_field.fill(p) - await satisfied_input_field.focus() + await satisfied_textbox.fill(p) + await satisfied_textbox.focus() await page.waitForTimeout(500) - await satisfied_input_field.press('Enter') + await satisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: p, exact: true })).toBeVisible() - await expect(satisfied_input_field).toHaveValue('') + await expect(satisfied_textbox).toHaveValue('') } - const unsatisfied_input_field = page.getByRole('textbox', { + const unsatisfied_textbox = page.getByRole('textbox', { name: 'Unsatisfied property', exact: true }) for (const q of ['isomorphism']) { - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') - await unsatisfied_input_field.fill(q) - await unsatisfied_input_field.focus() + await unsatisfied_textbox.fill(q) + await unsatisfied_textbox.focus() await page.waitForTimeout(500) - await unsatisfied_input_field.press('Enter') + await unsatisfied_textbox.press('Enter') await expect(page.getByRole('button', { name: q, exact: true })).toBeVisible() - await expect(unsatisfied_input_field).toHaveValue('') + await expect(unsatisfied_textbox).toHaveValue('') } await page @@ -183,7 +183,8 @@ test('contradictions are detected', async ({ page }) => { '/morphism-search/results?satisfied=regular_epimorphism~monomorphism&unsatisfied=split_epimorphism' ) - await expect(page.getByText('the requirements are inconsistent')).toBeVisible() + const body = page.locator('body') - await expect(page.getByText('isomorphism ⟹ split epimorphism')).toBeVisible() + await expect(body).toContainText('the requirements are inconsistent') + await expect(body).toContainText('isomorphism ⟹ split epimorphism') }) diff --git a/tests/morphisms.spec.ts b/tests/morphisms.spec.ts index 039b88975..b89d8650b 100644 --- a/tests/morphisms.spec.ts +++ b/tests/morphisms.spec.ts @@ -101,14 +101,16 @@ test('user can view morphism details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('basic example of a split epimorphism')).toBeVisible() - await expect(page.getByText('is a split epimorphism')).toBeVisible() - await expect(page.getByText('is a regular epimorphism')).toBeVisible() - await expect(page.getByText('is not an effective epimorphism')).toBeVisible() - await expect(page.getByText('is not an isomorphism')).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('basic example of a split epimorphism') + await expect(body).toContainText('is a split epimorphism') + await expect(body).toContainText('is a regular epimorphism') + await expect(body).toContainText('is not an effective epimorphism') + await expect(body).toContainText('is not an isomorphism') }) -test('user sees no unknown properties for a basic map', async ({ page }) => { +test('user sees no unknown properties for the terminal map', async ({ page }) => { await page.goto('/morphism/terminal-map') const unknown_properties_section = page.locator('section', { @@ -121,6 +123,7 @@ test('user can navigate to a related morphism', async ({ page }) => { await page.goto('/morphism/id_X', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Related morphisms:' }) .getByRole('link', { name: 'identity map of a group', exact: true @@ -141,11 +144,11 @@ test('user can navigate to the ambient category', async ({ page }) => { await page.goto('/morphism/fork-handle', { waitUntil: 'networkidle' }) await page + .locator('li', { hasText: 'Category:' }) .getByRole('link', { name: 'walking fork', exact: true }) - .first() .click() await expect( @@ -161,7 +164,7 @@ test('user can navigate to the ambient category', async ({ page }) => { test('user can open and close a proof for a property of a morphism', async ({ page }) => { await page.goto('/morphism/A3-S3-embedding', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is a normal monomorphism') }) + const claim = page.locator('li', { hasText: 'is a normal monomorphism' }) await expect(claim).toBeVisible() @@ -197,7 +200,7 @@ test('user can open a proof for a deduced satisfied property of a morphism', asy }) => { await page.goto('/morphism/terminal-map', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { has: page.getByText('is a strict epimorphism') }) + const claim = page.locator('li', { hasText: 'is a strict epimorphism' }) await expect(claim).toBeVisible() @@ -205,9 +208,9 @@ test('user can open a proof for a deduced satisfied property of a morphism', asy const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText('Since it is a regular epimorphism, it is a strict epimorphism') - ).toBeVisible() + await expect(popup).toContainText( + 'Since it is a regular epimorphism, it is a strict epimorphism' + ) }) test('user can open a proof for a deduced unsatisfied property of a morphism', async ({ @@ -215,9 +218,7 @@ test('user can open a proof for a deduced unsatisfied property of a morphism', a }) => { await page.goto('/morphism/multiply-2', { waitUntil: 'networkidle' }) - const claim = page.locator('li', { - has: page.getByText('is not a regular monomorphism') - }) + const claim = page.locator('li', { hasText: 'is not a regular monomorphism' }) await expect(claim).toBeVisible() @@ -225,7 +226,7 @@ test('user can open a proof for a deduced unsatisfied property of a morphism', a const popup = page.locator('.popup').filter({ hasText: 'Proof' }) - await expect( - popup.getByText('Assume for contradiction that it is a regular monomorphism.') - ).toBeVisible() + await expect(popup).toContainText( + 'Assume for contradiction that it is a regular monomorphism.' + ) }) diff --git a/tests/structure_selector.spec.ts b/tests/structure_selector.spec.ts index 4187cdc7e..4af862955 100644 --- a/tests/structure_selector.spec.ts +++ b/tests/structure_selector.spec.ts @@ -3,12 +3,10 @@ import { test, expect } from '@playwright/test' test('categories are selected by default', async ({ page }) => { await page.goto('/') - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await expect(selector).toHaveValue('category') @@ -17,12 +15,10 @@ test('categories are selected by default', async ({ page }) => { test('user can switch to functors', async ({ page }) => { await page.goto('/', { waitUntil: 'networkidle' }) - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await selector.selectOption('functor') @@ -42,12 +38,10 @@ test('user can switch to functors', async ({ page }) => { test('functors are selected on a functor route', async ({ page }) => { await page.goto('/functor-properties') - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await expect(selector).toHaveValue('functor') @@ -56,12 +50,10 @@ test('functors are selected on a functor route', async ({ page }) => { test('user can switch to morphisms', async ({ page }) => { await page.goto('/', { waitUntil: 'networkidle' }) - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await selector.selectOption('morphism') @@ -81,12 +73,10 @@ test('user can switch to morphisms', async ({ page }) => { test('morphisms are selected on a morphism route', async ({ page }) => { await page.goto('/morphism-properties') - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await expect(selector).toHaveValue('morphism') @@ -95,12 +85,10 @@ test('morphisms are selected on a morphism route', async ({ page }) => { test('user can switch to symmetric monoidal categories', async ({ page }) => { await page.goto('/', { waitUntil: 'networkidle' }) - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await selector.selectOption('symmetric_monoidal_category') @@ -122,12 +110,10 @@ test('symmetric monoidal categories are selected on a symmetric monoidal categor }) => { await page.goto('/symmetric_monoidal_category-properties') - const selector = page - .getByRole('combobox', { - name: 'Structure', - exact: true - }) - .first() + const selector = page.getByRole('combobox', { + name: 'Structure', + exact: true + }) await expect(selector).toBeVisible() await expect(selector).toHaveValue('symmetric_monoidal_category') diff --git a/tests/symmetric_monoidal_categories.spec.ts b/tests/symmetric_monoidal_categories.spec.ts index 0ac246da3..749acddd1 100644 --- a/tests/symmetric_monoidal_categories.spec.ts +++ b/tests/symmetric_monoidal_categories.spec.ts @@ -51,11 +51,13 @@ test('user can view symmetric monoidal category details', async ({ page }) => { }) ).toBeVisible() - await expect(page.getByText('tensor product of abelian groups')).toBeVisible() - await expect(page.getByText('is closed')).toBeVisible() - await expect(page.getByText('is cocomplete')).toBeVisible() - await expect(page.getByText('is not strict')).toBeVisible() - await expect(page.getByText('is not cartesian')).toBeVisible() + const body = page.locator('body') + + await expect(body).toContainText('tensor product of abelian groups') + await expect(body).toContainText('is closed') + await expect(body).toContainText('is cocomplete') + await expect(body).toContainText('is not strict') + await expect(body).toContainText('is not cartesian') }) test('user can navigate to the underlying category', async ({ page }) => { @@ -64,11 +66,11 @@ test('user can navigate to the underlying category', async ({ page }) => { }) await page + .locator('li', { hasText: 'Underlying category:' }) .getByRole('link', { name: 'category of sets', exact: true }) - .first() .click() await expect(