Skip to content

Commit 01979eb

Browse files
anuj-kumaryclaude
andcommitted
test(playwright): verify inverse relation types display correctly on both sides
Add E2E tests for #29687 that verify the UI shows the correct relation perspective on each side of an asymmetric relation (narrower/broader, hasPart/partOf) and that the correct type persists after page reload. Uses the base fixture with serverLoadReducers, beforeAll/afterAll API setup via getDefaultAdminAPIContext, addTermRelation API utility, and term.visitEntityPage() for navigation — matching the established GlossaryRelationsGraph test patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent a7cfbbb commit 01979eb

1 file changed

Lines changed: 149 additions & 0 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright 2026 Collate.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
import { expect, test } from '../../../support/fixtures/base';
14+
import { Glossary } from '../../../support/glossary/Glossary';
15+
import { GlossaryTerm } from '../../../support/glossary/GlossaryTerm';
16+
import { getDefaultAdminAPIContext } from '../../../utils/common';
17+
import { addTermRelation } from '../../../utils/ontologyStudio';
18+
19+
test.use({ storageState: 'playwright/.auth/admin.json' });
20+
21+
const glossary = new Glossary();
22+
const termFrom = new GlossaryTerm(glossary);
23+
const termTo = new GlossaryTerm(glossary);
24+
const termParent = new GlossaryTerm(glossary);
25+
const termChild = new GlossaryTerm(glossary);
26+
27+
test.beforeAll(
28+
'Seed glossary terms with inverse relations',
29+
async ({ browser }) => {
30+
const { apiContext, afterAction } =
31+
await getDefaultAdminAPIContext(browser);
32+
33+
await glossary.create(apiContext);
34+
await termFrom.create(apiContext);
35+
await termTo.create(apiContext);
36+
await termParent.create(apiContext);
37+
await termChild.create(apiContext);
38+
39+
await addTermRelation(apiContext, termFrom, termTo, 'narrower');
40+
await addTermRelation(apiContext, termParent, termChild, 'hasPart');
41+
42+
await afterAction();
43+
}
44+
);
45+
46+
test.afterAll('Clean up glossary data', async ({ browser }) => {
47+
const { apiContext, afterAction } = await getDefaultAdminAPIContext(browser);
48+
49+
await termFrom.delete(apiContext);
50+
await termTo.delete(apiContext);
51+
await termParent.delete(apiContext);
52+
await termChild.delete(apiContext);
53+
await glossary.delete(apiContext);
54+
55+
await afterAction();
56+
});
57+
58+
test.describe('Glossary Term — Inverse Relation Display (#29687)', () => {
59+
test('source term shows the authored relation type', async ({ page }) => {
60+
await termFrom.visitEntityPage(page);
61+
62+
const termToName =
63+
termTo.responseData?.displayName ?? termTo.data.displayName;
64+
65+
await expect(page.getByTestId(termToName)).toBeVisible();
66+
await expect(
67+
page
68+
.getByTestId('related-term-container')
69+
.getByText('Narrower', { exact: true })
70+
).toBeVisible();
71+
});
72+
73+
test('target term shows the inverse relation type', async ({ page }) => {
74+
await termTo.visitEntityPage(page);
75+
76+
const termFromName =
77+
termFrom.responseData?.displayName ?? termFrom.data.displayName;
78+
79+
await expect(page.getByTestId(termFromName)).toBeVisible();
80+
await expect(
81+
page
82+
.getByTestId('related-term-container')
83+
.getByText('Broader', { exact: true })
84+
).toBeVisible();
85+
});
86+
87+
test('inverse relation type persists after page reload', async ({
88+
page,
89+
}) => {
90+
await termTo.visitEntityPage(page);
91+
92+
const termFromName =
93+
termFrom.responseData?.displayName ?? termFrom.data.displayName;
94+
95+
await expect(
96+
page
97+
.getByTestId('related-term-container')
98+
.getByText('Broader', { exact: true })
99+
).toBeVisible();
100+
101+
const reloadRes = page.waitForResponse(
102+
(res) =>
103+
res.url().includes('/api/v1/glossaryTerms/name/') &&
104+
res.status() === 200
105+
);
106+
await page.reload();
107+
await reloadRes;
108+
109+
await expect(page.getByTestId(termFromName)).toBeVisible();
110+
await expect(
111+
page
112+
.getByTestId('related-term-container')
113+
.getByText('Broader', { exact: true })
114+
).toBeVisible();
115+
});
116+
117+
test('hasPart and partOf show on opposite sides of the relation', async ({
118+
page,
119+
}) => {
120+
await termParent.visitEntityPage(page);
121+
122+
const termChildName =
123+
termChild.responseData?.displayName ?? termChild.data.displayName;
124+
125+
await expect(page.getByTestId(termChildName)).toBeVisible();
126+
await expect(
127+
page
128+
.getByTestId('related-term-container')
129+
.getByText('Has Part', { exact: true })
130+
).toBeVisible();
131+
132+
await termChild.visitEntityPage(page);
133+
134+
const termParentName =
135+
termParent.responseData?.displayName ?? termParent.data.displayName;
136+
137+
await expect(page.getByTestId(termParentName)).toBeVisible();
138+
await expect(
139+
page
140+
.getByTestId('related-term-container')
141+
.getByText('Part Of', { exact: true })
142+
).toBeVisible();
143+
await expect(
144+
page
145+
.getByTestId('related-term-container')
146+
.getByText('Has Part', { exact: true })
147+
).not.toBeVisible();
148+
});
149+
});

0 commit comments

Comments
 (0)