Skip to content

Commit d2ca3f3

Browse files
committed
test(docs): create tests for Writerside instances
- Remove outdated `webhelp.spec.ts` and related utility files to streamline test coverage. - Introduce `article.spec.ts` for modernized and standardized testing of documentation pages. - Consolidate redundant code and improve reusability with updated utilities and constants.
1 parent f43b098 commit d2ca3f3

File tree

260 files changed

+715
-444
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

260 files changed

+715
-444
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ To run these tests locally, follow the next steps:
262262
2. Open the last successful build of [Reference Docs](https://buildserver.labs.intellij.net/buildConfiguration/Kotlin_KotlinSites_KotlinlangTeamcityDsl_BuildReferenceDocs?branch=&mode=builds#all-projects) on TeamCity.
263263
3. Download the artifacts of this build and place them in the `dist` folder.
264264
4. Run the tests locally with the following command `yarn run test:e2e`
265-
5. Run the tests in docker container with the following command `docker compose -f docker-compose-e2e-statics.yml up --build --exit-code-from playwright`
265+
5. Run the tests in docker container with the following command `docker compose -f docker-compose-e2e.yml up --build --exit-code-from playwright`
266266
267267
## API references tests
268268

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@
138138
"generate-redirects": "node scripts/generate-redirect-pages.js",
139139
"lint": "next lint",
140140
"test": "playwright test test",
141-
"test:ci": "playwright test test/production",
141+
"test:ci": "playwright test test/production test/e2e/docs",
142142
"test:e2e": "playwright test test/e2e",
143143
"test:e2e:ci": "CI=true playwright test test/e2e",
144144
"test:e2e:headed": "playwright test test/e2e --headed",

scripts/run-e2e-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ set +x
44
set -o pipefail
55
set -u
66

7-
docker compose -f docker-compose-e2e-statics.yml up --exit-code-from playwright
7+
docker compose -f docker-compose-e2e.yml up --exit-code-from playwright

test/e2e/docs/article.spec.ts

Lines changed: 383 additions & 0 deletions
Large diffs are not rendered by default.

test/e2e/docs/docs.spec.ts

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
import { expect, test } from '@playwright/test';
2+
import { parse } from 'path';
3+
import { checkScreenshot, testSelector } from '../../utils';
4+
import { RESOLUTIONS } from '../visual-constants';
5+
import { WebHelpPage } from './page';
6+
7+
const DOCS_URLS = [`/docs/home.html`, '/docs/multiplatform/get-started.html'];
8+
9+
for (let index = 0, docsLength = DOCS_URLS.length; index < docsLength; index++) {
10+
const docsUrl = DOCS_URLS[index];
11+
12+
for (const [resolutionName, resolution] of Object.entries(RESOLUTIONS)) {
13+
test.describe(`Docs: ${parse(docsUrl).dir}/ on ${resolutionName}`, () => {
14+
test.beforeEach(async ({ page }) => {
15+
await page.setViewportSize(resolution);
16+
17+
const webHelpPage = new WebHelpPage(page, docsUrl);
18+
await webHelpPage.init();
19+
});
20+
21+
test(`Should render table of contents properly`, async ({ page }) => {
22+
test.skip(resolutionName !== 'desktop');
23+
24+
const element = page.locator(testSelector('toc'));
25+
26+
await expect(element).toHaveCount(1);
27+
await expect(element).toBeVisible();
28+
29+
await checkScreenshot(element);
30+
});
31+
32+
test(`Should open page item properly`, async ({ page }) => {
33+
test.skip(resolutionName !== 'desktop');
34+
35+
const element = page.locator(testSelector('toc')).first();
36+
37+
const tocItem = element.locator(testSelector('internal-link toc-item')).first();
38+
const link = new URL(await tocItem.getAttribute('href'), page.url());
39+
40+
await tocItem.click();
41+
expect(page.url()).toBe(link.href);
42+
});
43+
44+
test(`Should render table of contents with expanded item properly`, async ({ page }) => {
45+
test.skip(resolutionName !== 'desktop');
46+
47+
const toc = page.locator(testSelector('toc'));
48+
49+
await expect(toc).toHaveCount(1);
50+
await expect(toc).toBeVisible();
51+
52+
const item = toc.locator(`:scope > li:has(${testSelector('toc-item')})`).first();
53+
await expect(item).toBeVisible();
54+
55+
const itemExpander = item.locator(testSelector('toc-expander')).first();
56+
await expect(item).toBeVisible();
57+
58+
const itemNext = item.locator(`:scope + li`).first();
59+
const itemNextText = await itemNext.textContent();
60+
61+
await itemExpander.click();
62+
63+
expect(await itemNext.textContent()).not.toBe(itemNextText);
64+
65+
await checkScreenshot(item);
66+
});
67+
68+
test(`Should render header properly`, async ({ page }) => {
69+
const element = page.locator('.kt-header');
70+
await expect(element).toBeVisible();
71+
await checkScreenshot(element, { mask: [page.locator('.kt-header__product-version')] });
72+
});
73+
74+
test(`Should render footer properly`, async ({ page }) => {
75+
const element = page.locator(testSelector('footer'));
76+
await expect(element).toBeVisible();
77+
await checkScreenshot(element);
78+
});
79+
80+
test(`Should render docs switcher properly`, async ({ page }) => {
81+
const switcher = page.locator('[data-e2e="toc-subnav"]');
82+
83+
if (resolutionName !== 'desktop') {
84+
await expect(switcher).not.toBeVisible();
85+
return;
86+
}
87+
88+
await expect(switcher).toHaveCount(1);
89+
await expect(switcher).toBeVisible();
90+
91+
const items = switcher.locator('[data-rs-internal=switcher__option]');
92+
await expect(items).toHaveCount(2);
93+
94+
await expect(items.nth(index).locator(':scope[class*=_selected_]')).toBeVisible();
95+
96+
const inactiveItemIndex = (index + 1) % docsLength;
97+
98+
const inactiveItem = items.nth(inactiveItemIndex);
99+
await expect(inactiveItem.locator(':scope[class*=_selected_]')).not.toBeVisible();
100+
101+
await checkScreenshot(switcher);
102+
103+
await inactiveItem.click();
104+
await expect(page).toHaveURL(DOCS_URLS[inactiveItemIndex]);
105+
});
106+
107+
test(`Should open quick search and show results`, async ({ page }) => {
108+
await page.locator(testSelector('search-button')).click();
109+
await expect(page.locator(testSelector('search-quick'))).toBeVisible();
110+
111+
const input = page.locator(testSelector('input__inner'));
112+
await expect(input).toBeVisible();
113+
await input.fill('grammar');
114+
115+
const results = page.locator(testSelector('search-results'));
116+
await expect(results).toBeVisible();
117+
118+
const items = page.locator(testSelector('list-item'));
119+
expect(await items.count()).toBeGreaterThan(1);
120+
121+
await checkScreenshot(page.locator(testSelector('search-quick')), {
122+
mask: [page.locator(testSelector('result-content')), page.locator(testSelector('search-results'))],
123+
});
124+
});
125+
126+
test(`Should close quick search on Escape`, async ({ page }) => {
127+
await page.locator(testSelector('search-button')).click();
128+
await expect(page.locator(testSelector('search-quick'))).toBeVisible();
129+
130+
await page.keyboard.press('Escape');
131+
await expect(page.locator(testSelector('search-quick'))).not.toBeVisible();
132+
});
133+
134+
test(`Should open full search from quick search`, async ({ page }) => {
135+
await page.locator(testSelector('search-button')).click();
136+
await expect(page.locator(testSelector('search-quick'))).toBeVisible();
137+
138+
const input = page.locator(testSelector('input__inner'));
139+
await input.fill('grammar');
140+
await expect(page.locator(testSelector('search-results'))).toBeVisible();
141+
142+
const fullSearchButton = page.locator(testSelector('full-search-button'));
143+
144+
if (resolutionName === 'mobile') {
145+
await expect(fullSearchButton).not.toBeVisible();
146+
return;
147+
}
148+
149+
await fullSearchButton.click();
150+
await expect(page.locator(testSelector('search-full'))).toBeVisible();
151+
152+
await expect(page).toHaveURL(/\?q=grammar&s=full/);
153+
154+
const fullResults = page.locator(testSelector('search-full')).locator(testSelector('search-results'));
155+
await expect(fullResults).toBeVisible();
156+
157+
await checkScreenshot(page.locator(testSelector('search-full')), {
158+
mask: [page.locator(testSelector('result-content')), page.locator(testSelector('search-results'))],
159+
});
160+
});
161+
162+
test(`Should close full search`, async ({ page }) => {
163+
await page.locator(testSelector('search-button')).click();
164+
await expect(page.locator(testSelector('search-quick'))).toBeVisible();
165+
166+
const input = page.locator(testSelector('input__inner'));
167+
await input.fill('grammar');
168+
await expect(page.locator(testSelector('search-results'))).toBeVisible();
169+
170+
const fullSearchButton = page.locator(testSelector('full-search-button'));
171+
172+
if (resolutionName === 'mobile') {
173+
await expect(fullSearchButton).not.toBeVisible();
174+
return;
175+
}
176+
177+
await fullSearchButton.click();
178+
await expect(page.locator(testSelector('search-full'))).toBeVisible();
179+
180+
await page.locator(testSelector('close-search')).click();
181+
await expect(page.locator(testSelector('search-full'))).not.toBeVisible();
182+
});
183+
});
184+
}
185+
}

test/e2e/docs/page.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { Page } from '@playwright/test';
2+
import { testSelector } from '../../utils';
3+
import { BasePage } from '../../page/base-page';
4+
5+
export class WebHelpPage implements BasePage {
6+
readonly page: Page;
7+
readonly url: string;
8+
9+
constructor(page, url) {
10+
this.page = page;
11+
this.url = url;
12+
}
13+
14+
async init() {
15+
await this.page.goto(this.url);
16+
17+
await this.page.waitForSelector(testSelector('kt-app__article'));
18+
}
19+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[data-test="toc"] {
2+
background: lavender !important;
3+
}
4+
5+
[data-test="toc"] > * {
6+
visibility: hidden !important;
7+
}
8+
9+
.kt-header {
10+
background: #3c3d40 !important;
11+
}
12+
13+
.kt-header > * {
14+
visibility: hidden !important;
15+
}
16+
17+
[data-test="footer"] {
18+
background: #6B70FC !important;
19+
}
20+
21+
[data-test="footer"] > * {
22+
visibility: hidden !important;
23+
}
24+
25+
[data-test="virtual-toc"] {
26+
background: #CC7832 !important;
27+
}
28+
29+
[data-test="virtual-toc"] > * {
30+
visibility: hidden !important;
31+
}
32+
33+
[data-test="article"] {
34+
background: #d4f1ec !important;
35+
}
36+
37+
[data-test="article"] > * {
38+
visibility: hidden !important;
39+
}
40+
41+
[data-e2e="toc-subnav"] {
42+
background: hotpink !important;
43+
}
44+
45+
[data-e2e="toc-subnav"] > * {
46+
visibility: hidden !important;
47+
}

test/e2e/hide-sticky-banner.css

Lines changed: 0 additions & 3 deletions
This file was deleted.

test/e2e/multiplatform/multiplatform.spec.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect, Locator, test } from '@playwright/test';
22
import { MultiplatformPage } from '../../page/multiplatform-page';
33
import { checkAnchor, checkScreenshot } from '../../utils';
4-
import { checkFullPageScreenshot } from '../utils';
4+
import { checkFullPageScreenshot } from '../../utils';
55

66
test.describe('Multiplatform landing page', async () => {
77
let multiplatformPage: MultiplatformPage;
@@ -15,9 +15,7 @@ test.describe('Multiplatform landing page', async () => {
1515
const { main, page } = multiplatformPage;
1616

1717
await checkFullPageScreenshot(page, {
18-
mask: [
19-
main.locator('[data-testid*="share-what-chip-content-"]')
20-
]
18+
mask: [main.locator('[data-testid*="share-what-chip-content-"]')],
2119
});
2220
});
2321

@@ -35,7 +33,7 @@ test.describe('Multiplatform landing page', async () => {
3533
await expect(heroActionButton).toBeVisible();
3634

3735
await checkScreenshot(multiplatformPage.heroBanner, {
38-
stylePath: 'test/e2e/hide-sticky-banner.css'
36+
stylePath: 'test/e2e/hide-sticky-banner.css',
3937
});
4038

4139
const href = await heroActionButton.getAttribute('href');
@@ -55,7 +53,7 @@ test.describe('Multiplatform landing page', async () => {
5553

5654
for (const anchor of await anchors.all()) {
5755
// Check that the "both-logic-ui-tab" chip is selected by default
58-
if (await anchor.getAttribute('id') === 'choose-share-what-both-logic-ui-tab') {
56+
if ((await anchor.getAttribute('id')) === 'choose-share-what-both-logic-ui-tab') {
5957
await anchor.scrollIntoViewIfNeeded();
6058
await checkChooseWhatToShare(multiplatformPage, anchor);
6159
continue;
@@ -89,7 +87,7 @@ test.describe('Multiplatform landing page', async () => {
8987
await expect(multiplatformPage.ctaBlockAction).not.toBeEmpty();
9088

9189
await checkScreenshot(multiplatformPage.ctaBlock, {
92-
stylePath: 'test/e2e/hide-sticky-banner.css'
90+
stylePath: 'test/e2e/hide-sticky-banner.css',
9391
});
9492

9593
const href = await multiplatformPage.ctaBlockAction.getAttribute('href');
@@ -124,7 +122,7 @@ async function checkChooseWhatToShare({ page, main, shareWhatBlock }: Multiplatf
124122
await expect(link).not.toBeEmpty();
125123

126124
await checkScreenshot(shareWhatBlock, {
127-
stylePath: 'test/e2e/hide-sticky-banner.css'
125+
stylePath: 'test/e2e/hide-sticky-banner.css',
128126
});
129127

130128
// Check that links work as links

0 commit comments

Comments
 (0)