Skip to content

Commit 44b9915

Browse files
authored
Merge pull request #378 from ReadAlongs/dev.del/feat-editor-e2e
feat: extended studio-web end-to-end test suite to include tests for editor interface
2 parents 2e5216a + 1813969 commit 44b9915

File tree

14 files changed

+592
-32
lines changed

14 files changed

+592
-32
lines changed

.github/workflows/end-to-end-tests.yml

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ on:
66
- push
77
- workflow_call
88
jobs:
9-
test-suites:
9+
web-component-suites:
10+
name: Web-Component tests and utilities verification
1011
runs-on: ubuntu-latest
1112
# Stop the occasional rogue instance before the 6h GitHub limit
1213
timeout-minutes: 15
@@ -22,10 +23,6 @@ jobs:
2223
- name: Install everything
2324
run: npm install
2425

25-
- name: Ng test for studio-web
26-
run: |
27-
npx nx build web-component
28-
npx nx test:once studio-web
2926
- name: Cypress run for web-component
3027
uses: cypress-io/github-action@v6
3128
with:
@@ -54,15 +51,15 @@ jobs:
5451
npx nx bundle web-component
5552
git status
5653
git diff --word-diff=porcelain --word-diff-regex=... --color | perl -ple 's/^(\x1b[^ -+]{0,6})? (.{81,})$/$1 . " " . substr($2, 0, 40) . " [... " . (length($2)-80) . " bytes ...] " . substr($2, -40)/ex'
57-
playwright-tests:
58-
name: Run Playwright test-suites
54+
studio-e2e-tests:
55+
name: Studio Web test-suites
5956
timeout-minutes: 60
6057
runs-on: ubuntu-latest
6158
strategy:
6259
fail-fast: false
6360
matrix:
64-
shardIndex: [1, 2, 3, 4]
65-
shardTotal: [4]
61+
shardIndex: [1, 2, 3]
62+
shardTotal: [3]
6663
steps:
6764
- uses: actions/checkout@v4
6865
- uses: actions/setup-node@v4
@@ -72,22 +69,26 @@ jobs:
7269
run: |
7370
git clone https://github.com/ReadAlongs/Studio
7471
cd Studio
75-
pip install -e . -r requirements.api.txt
72+
pip install -e .[api]
7673
./run-web-api.sh &
7774
# wait for the API to be up
7875
curl --retry 20 --retry-delay 1 --retry-all-errors http://localhost:8000/api/v1/langs
7976
- name: Install everything
8077
run: npm install
8178
- name: Install dependencies
8279
run: npm ci
80+
- name: Ng test for studio-web
81+
run: |
82+
npx nx build web-component
83+
npx nx test:once studio-web
8384
- name: Run studio-web in the background
8485
run: |
8586
npx nx build web-component
8687
npx nx run-many --targets=serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6 &
8788
8889
# wait for the studio web to be up
89-
sleep 100
90-
curl --retry 20 --retry-delay 30 --retry-all-errors http://localhost:4200
90+
sleep 50
91+
curl --retry 20 --retry-delay 10 --retry-all-errors http://localhost:4200 > /dev/null
9192
- name: Run Playwright tests for studio-web
9293
run: |
9394
npx playwright install --with-deps chromium
@@ -102,8 +103,8 @@ jobs:
102103
merge-reports:
103104
# Merge reports after playwright-tests, even if some shards have failed
104105
if: ${{ !cancelled() }}
105-
needs: [playwright-tests]
106-
name: "Merge playwright reports"
106+
needs: [studio-e2e-tests]
107+
name: "Merge playwright reports from studio-web end-to-end tests"
107108
runs-on: ubuntu-latest
108109
steps:
109110
- uses: actions/checkout@v4
@@ -123,10 +124,10 @@ jobs:
123124
pattern: blob-report-*
124125
merge-multiple: true
125126

126-
- name: Merge into HTML Report
127+
- name: Merge into a single HTML Report
127128
run: npx playwright merge-reports --reporter=html,github ./all-blob-reports
128129

129-
- name: Upload HTML report
130+
- name: Upload single HTML report
130131
uses: actions/upload-artifact@v4
131132
with:
132133
name: html-report--attempt-${{ github.run_attempt }}

README.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,18 @@ This mono repo, formerly called Web-Component, now called Studio-Web, combines f
3131
- [Studio-Web](#studio-web)
3232
- [Understanding where the components come from when you run locally](#understanding-where-the-components-come-from-when-you-run-locally)
3333
- [Testing](#testing)
34+
- [TL;DR](#tldr)
3435
- [Web-Component](#web-component-1)
3536
- [Studio-Web](#studio-web-1)
37+
- [End-to-End tests](#end-to-end-tests)
3638
- [Internationalization (i18n) and localization (l10n)](#internationalization-i18n-and-localization-l10n)
37-
- [Build \& Publish](#build--publish-the-web-component)
39+
- [Build \& Publish the Web Component](#build--publish-the-web-component)
3840
- [Preparing to publish the Web Component \& Angular Wrapper](#preparing-to-publish-the-web-component--angular-wrapper)
3941
- [Web Component \& Angular Wrapper - via a tag push](#web-component--angular-wrapper---via-a-tag-push)
4042
- [Web Component \& Angular Wrapper - manually - please don't do this!](#web-component--angular-wrapper---manually---please-dont-do-this)
41-
- [Build \& Deploy the Studio-Web App](#build--deploy-the-studio-web-app)
43+
- [Build \& Deploy the Studio-Web app](#build--deploy-the-studio-web-app)
44+
- [Automated Deployment](#automated-deployment)
45+
- [Build Studio-Web and deploy it somewhere else](#build-studio-web-and-deploy-it-somewhere-else)
4246
- [Maintainers](#maintainers)
4347
- [Contributing](#contributing)
4448
- [Acknowledgements](#acknowledgements)
@@ -189,6 +193,10 @@ to serve or import. In the instructions above, we actually show two methods you
189193
npm install
190194
npx nx run-many --targets=serve-test-data,serve,test:once --projects=web-component
191195
# Ctrl-C once "✔ All specs passed! 01:01 34 34" appears (34 specs as of writing)
196+
npx playwright install --with-deps firefox chromium webkit
197+
npx nx run-many --targets=serve-test-data,serve-web-api,serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6
198+
npx nx e2e studio-web
199+
#Expect "47 passed (4.6m)" (47 tests as of writing)
192200
npx nx test:once studio-web
193201
# Expect "TOTAL: 25 SUCCESS" (25 tests as of writing)
194202
npx nx extract-i18n studio-web
@@ -224,10 +232,29 @@ Alternatively run together as:
224232
#### Studio-Web
225233

226234
To run the unit tests for Studio-Web, first build `web-component` in one of the ways listed
227-
above (or just `npx nx build web-component`) if you have not already done so, and then run:
235+
above (or just `npx nx build web-component`) if you have not already done so, and then
236+
run:
228237

229238
npx nx test:once studio-web
230239

240+
##### End-to-End tests
241+
242+
To run the end-to-end tests for Studio-Web, please check the following:
243+
244+
- Ensure that you have built the `web-component` (run `npx nx build web-component`)
245+
- Check that `studio-cli` is installed and running (run `npx nx serve-web-api studio-web`)
246+
- Confirm that `studio-web` is up and running (run `npx nx run-many --targets=serve,serve-fr,serve-es --projects=studio-web --parallel 3`). Your browser must be able to load `http://localhost:4200/` before you proceed.
247+
- Verify that `playwright` is installed and configured (run `npx playwright install --with-deps firefox chromium webkit`)
248+
249+
Alternatively run together as:
250+
251+
npx playwright install --with-deps firefox chromium webkit && npx nx run-many --targets=serve-test-data,serve-web-api,serve,serve-fr,serve-es --projects=web-component,studio-web --parallel 6
252+
253+
Once you have confirmed that everything is online and working run:
254+
`npx nx e2e studio-web` and wait for the report.
255+
256+
**PS**: If you want to run a spec interactively you can run `npx nx e2e-ui studio-web` to get playwright interactive user interface.
257+
231258
### Internationalization (i18n) and localization (l10n)
232259

233260
`studio-web` is localized in French and Spanish. When you add new strings that need localizing,

packages/studio-web/playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default defineConfig({
2121
/* Retry on CI only */
2222
retries: process.env.CI ? 2 : 3,
2323
/* Opt out of parallel tests on CI. */
24-
workers: process.env.CI ? 1 : 2,
24+
workers: process.env.CI ? 4 : undefined,
2525
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
2626
reporter: process.env.CI ? [["blob", { open: "never" }]] : "html",
2727
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */

packages/studio-web/src/app/app.component.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
ReadAlong Studio
44
</span>
55
<span class="nav-spacer"></span>
6-
<button class="d-md-none" mat-button [matMenuTriggerFor]="menu">
6+
<button
7+
class="d-md-none"
8+
data-test-id="menu-toggle"
9+
mat-button
10+
[matMenuTriggerFor]="menu"
11+
>
712
<mat-icon>menu</mat-icon>
813
</button>
914
<mat-menu #menu="matMenu">

packages/studio-web/src/app/shared/download/download.service.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,14 @@ Please host all assets on your server, include the font and package imports defi
165165
}
166166

167167
registerDownloadEvent(selectedOutputFormat: SupportedOutputs, from: string) {
168-
const win = window;
169-
(win as any).plausible(`Download`, {
170-
props: { fileType: selectedOutputFormat, downloadSource: from },
171-
});
168+
try {
169+
const win = window;
170+
(win as any).plausible(`Download`, {
171+
props: { fileType: selectedOutputFormat, downloadSource: from },
172+
});
173+
} catch (err) {
174+
console.error(err);
175+
}
172176
}
173177

174178
async createSingleFileBlob(
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { test, expect } from "@playwright/test";
2+
import { testAssetsPath, disablePlausible } from "../test-commands";
3+
test.describe.configure({ mode: "parallel" });
4+
test("should check editor UI", async ({ page, isMobile }) => {
5+
await page.goto("/", { waitUntil: "load" });
6+
7+
await disablePlausible(page);
8+
if (isMobile) {
9+
await page.getByTestId("menu-toggle").click();
10+
}
11+
await page.getByRole("button", { name: /Editor/ }).click();
12+
await expect(
13+
page.getByRole("button", { name: "Take the tour!" }),
14+
"Tour button is visible",
15+
).toBeVisible();
16+
await expect(
17+
page.locator("#updateRAS"),
18+
"Choose file is visible",
19+
).toBeVisible();
20+
let fileChooserPromise = page.waitForEvent("filechooser");
21+
await page.locator("#updateRAS").click();
22+
let fileChooser = await fileChooserPromise;
23+
fileChooser.setFiles(testAssetsPath + "sentence-paragr.html");
24+
//check audio bar
25+
/**
26+
* We are using css classes instead of test-id because this is an external plugin
27+
* failure here means the plugin version has changed we should test impact on our app
28+
*/
29+
30+
await expect(
31+
page.locator("#audioToolbar"),
32+
"audio bar should exist",
33+
).toHaveCount(1);
34+
await expect(
35+
page.locator("segment.wavesurfer-segment"),
36+
"should seven audio segments",
37+
).toHaveCount(7);
38+
await expect(
39+
page.locator("segment.wavesurfer-segment:first-of-type > .segment-content"),
40+
"audio segments text should be editable",
41+
).toHaveAttribute("contenteditable", "true");
42+
await expect(
43+
page.locator(
44+
"segment.wavesurfer-segment:first-of-type > .wavesurfer-handle",
45+
),
46+
"audio segments boundaries should exist",
47+
).toHaveCount(2);
48+
49+
//check readalong
50+
await expect(
51+
page.locator("#readalongContainer"),
52+
"should check that readalong is loading",
53+
).not.toBeEmpty();
54+
const header = page.locator(
55+
"#readalongContainer span[slot=read-along-header]",
56+
);
57+
await expect(header, "should have correct title").toContainText(
58+
"Sentence Paragraph Page",
59+
);
60+
await expect(header, "should have editable title").toHaveAttribute(
61+
"contenteditable",
62+
"true",
63+
);
64+
const subheader = page.locator(
65+
"#readalongContainer span[slot=read-along-subheader]",
66+
);
67+
await expect(subheader, "should have correct subtitle").toContainText(
68+
"by me",
69+
);
70+
await expect(subheader, "should have editable subtitle").toHaveAttribute(
71+
"contenteditable",
72+
"true",
73+
);
74+
await page.locator("#t0b0d0p1s0").scrollIntoViewIfNeeded();
75+
await expect(
76+
page.locator("#t0b0d0p0s0").getByLabel("Remove translation"),
77+
"should have translation for first paragraph first sentence",
78+
).toBeVisible();
79+
await expect(
80+
page.locator("#t0b0d0p0s1").getByRole("button", { name: "add" }),
81+
"should not have translation for first paragraph second sentence",
82+
).toBeVisible();
83+
await expect(
84+
page.locator("#t0b0d0p1s0").getByLabel("Remove translation"),
85+
"should have translation for second paragraph ",
86+
).toBeVisible();
87+
await expect(
88+
page.locator("#fileElem--t0b0d0"),
89+
"should not have image on first page",
90+
).toHaveCount(1);
91+
await expect(
92+
page.locator("#t0b0d1 img"),
93+
"should have image on second page",
94+
).toHaveCount(1);
95+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { test, expect } from "@playwright/test";
2+
import { testAssetsPath, editorDefaultBeforeEach } from "../test-commands";
3+
test.describe.configure({ mode: "parallel" });
4+
5+
test("should edit images (editor)", async ({ page, isMobile }) => {
6+
await expect(async () => {
7+
await editorDefaultBeforeEach(page, isMobile);
8+
}).toPass();
9+
await page.locator("#updateRAS").waitFor({ state: "visible" });
10+
await expect(
11+
page.locator("#fileElem--t0b0d0"),
12+
"should not have image on first page",
13+
).toHaveCount(1);
14+
//upload a photo to page 1
15+
let fileChooserPromise = page.waitForEvent("filechooser");
16+
page.locator("#fileElem--t0b0d0").dispatchEvent("click");
17+
18+
let fileChooser = await fileChooserPromise;
19+
fileChooser.setFiles(testAssetsPath + "page1.png");
20+
await expect(
21+
page.locator("#t0b0d0 img"),
22+
"should have image on first page",
23+
).toHaveCount(1);
24+
//delete photo page 2 and re-add
25+
const progressBar = page.getByTestId("progress-bar");
26+
const progressBarBoundingBox = await progressBar.boundingBox();
27+
28+
await progressBar.click({
29+
force: true,
30+
position: {
31+
x: progressBarBoundingBox?.x || 0,
32+
y: progressBarBoundingBox ? progressBarBoundingBox.width * 0.9 : 0,
33+
},
34+
});
35+
await page.locator("#t0b0d1").getByTestId("delete-button").click();
36+
await expect(
37+
page.locator("#fileElem--t0b0d1"),
38+
"should remove image on second page",
39+
).toHaveCount(1);
40+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { test, expect } from "@playwright/test";
2+
import { editorDefaultBeforeEach } from "../test-commands";
3+
test.describe.configure({ mode: "parallel" });
4+
5+
test("should edit translations (editor)", async ({ page, isMobile }) => {
6+
await expect(async () => {
7+
await editorDefaultBeforeEach(page, isMobile);
8+
}).toPass();
9+
await page.locator("#t0b0d0p0s0translation").waitFor({ state: "visible" });
10+
//edit first sentence translation
11+
await page.locator("#t0b0d0p0s0translation").fill("Un vrai test.");
12+
await expect(page.locator("#t0b0d0p0s0translation")).toContainText(
13+
"Un vrai test.",
14+
);
15+
//add translation to second sentence
16+
await page
17+
.locator("#t0b0d0p0s1")
18+
.getByTestId("add-translation-button")
19+
.click();
20+
await page.locator("#t0b0d0p0s1translation").fill("Phrase.");
21+
//remove third sentence
22+
await page
23+
.locator("#t0b0d0p1s0")
24+
.getByTestId("remove-translation-button")
25+
.click();
26+
await page
27+
.locator("#t0b0d0p1s0")
28+
.getByTestId("add-translation-button")
29+
.waitFor({ state: "visible" });
30+
//toggle translations
31+
await page.getByTestId("translation-toggle").click();
32+
await expect(
33+
page.locator(".sentence__translation.invisible"),
34+
" translations should be hidden",
35+
).not.toHaveCount(0);
36+
await page.getByTestId("translation-toggle").click();
37+
await expect(
38+
page.locator(".sentence__translation.invisible"),
39+
" translations should not be hidden",
40+
).toHaveCount(0);
41+
await expect(
42+
page.getByTestId("translation-line"),
43+
" translations should not be hidden",
44+
).toHaveCount(2);
45+
});

0 commit comments

Comments
 (0)