Skip to content

Commit b3cbe8d

Browse files
e2e test for import and minor accessibility tweaks in support
Use the .org proxy in e2e too so we can test with an actual build.
1 parent 6e7310f commit b3cbe8d

File tree

8 files changed

+99
-6
lines changed

8 files changed

+99
-6
lines changed

src/components/ActionNameCard.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@ const ActionNameCard = ({
162162
? { bgColor: "transparent", size: "lg" }
163163
: { bgColor: "gray.25", size: "sm" })}
164164
_placeholder={{ opacity: 0.8, color: "gray.900" }}
165+
aria-label={intl.formatMessage({
166+
id: "action-name-placeholder",
167+
})}
165168
placeholder={intl.formatMessage({
166169
id: "action-name-placeholder",
167170
})}

src/deployment/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ export type DeploymentConfigFactory = (
1313
// This is configured via a vite alias, defaulting to ./default
1414
import { default as df } from "theme-package";
1515
import { BoxProps } from "@chakra-ui/react";
16+
import { flags } from "../flags";
1617
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1718
const deploymentFactory: DeploymentConfigFactory = df;
1819
export const deployment = (() => {
1920
const deployment = deploymentFactory(import.meta.env);
20-
if (import.meta.env.DEV) {
21+
if (import.meta.env.DEV || flags.e2e) {
2122
return {
2223
...deployment,
23-
// Sidestep CORS issues in development. See vite.config.ts.
24+
// Sidestep CORS issues in development/e2e. See vite.config.ts.
2425
activitiesBaseUrl: "/microbit-org-proxy/classroom/activities/",
2526
};
2627
}

src/e2e/app/data-samples.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ export class DataSamplesPage {
6363
await expect(this.heading).toBeVisible({ timeout: 10000 });
6464
}
6565

66+
async expectActions(expectedActions: string[]) {
67+
const actionInputs = this.page.getByRole("textbox", {
68+
name: "Name of action",
69+
});
70+
await expect(actionInputs).toHaveCount(expectedActions.length, {
71+
timeout: 10_000,
72+
});
73+
let i = 0;
74+
for (const input of await actionInputs.all()) {
75+
await expect(input).toHaveValue(expectedActions[i++]);
76+
}
77+
}
78+
6679
async trainModel() {
6780
await this.page.getByRole("button", { name: "Train model" }).click();
6881
return new TrainModelDialog(this.page);

src/e2e/app/import-page.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { Locator, type Page, expect } from "@playwright/test";
2+
3+
export class ImportPage {
4+
private readonly url: string;
5+
private nameInputField: Locator;
6+
private startSessionBtn: Locator;
7+
8+
constructor(public readonly page: Page) {
9+
this.url = `http://localhost:5173${
10+
process.env.CI ? process.env.BASE_URL : "/"
11+
}`;
12+
13+
this.startSessionBtn = page.getByRole("button", { name: "Start session" });
14+
this.nameInputField = page.getByRole("textbox", { name: "Name" });
15+
}
16+
17+
async gotoSimpleAIExerciseTimer() {
18+
// The import process relies on the e2e flag in this query string
19+
// for the proxy to be used.
20+
const query =
21+
"flag=e2e&id=simple-ai-exercise-timer&project=Project%3A%20Simple%20AI%20exercise%20timer&name=Simple%20AI%20exercise%20timer&editors=makecode";
22+
return this.page.goto(`${this.url}import?${query}`);
23+
}
24+
25+
expectName(expected: string) {
26+
return expect(this.nameInputField).toHaveValue(expected);
27+
}
28+
29+
async startSession() {
30+
// Might still be loading.
31+
await expect(this.startSessionBtn).toBeEnabled({
32+
timeout: 5_000,
33+
});
34+
await this.startSessionBtn.click();
35+
}
36+
37+
async expectOnPage() {
38+
await expect(this.page.getByText("New session setup")).toBeVisible();
39+
await expect(this.nameInputField).toBeVisible();
40+
await expect(this.startSessionBtn).toBeVisible();
41+
}
42+
}

src/e2e/fixtures.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ import { DataSamplesPage } from "./app/data-samples";
99
import { TestModelPage } from "./app/test-model-page";
1010
import { NewPage } from "./app/new-page";
1111
import { OpenSharedProjectPage } from "./app/open-shared-project-page";
12+
import { ImportPage } from "./app/import-page";
1213

1314
type MyFixtures = {
1415
homePage: HomePage;
1516
newPage: NewPage;
1617
dataSamplesPage: DataSamplesPage;
1718
testModelPage: TestModelPage;
1819
openSharedProjectPage: OpenSharedProjectPage;
20+
importPage: ImportPage;
1921
};
2022

2123
export const test = base.extend<MyFixtures>({
@@ -36,4 +38,7 @@ export const test = base.extend<MyFixtures>({
3638
openSharedProjectPage: async ({ page }, use) => {
3739
await use(new OpenSharedProjectPage(page));
3840
},
41+
importPage: async ({ page }, use) => {
42+
await use(new ImportPage(page));
43+
},
3944
});

src/e2e/import-project.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* (c) 2024, Micro:bit Educational Foundation and contributors
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*/
6+
import { test } from "./fixtures";
7+
8+
test.describe("import project (microbit.org case)", () => {
9+
test.beforeEach(async ({ homePage }) => {
10+
await homePage.setupContext();
11+
});
12+
13+
test("confirm and import", async ({ importPage, dataSamplesPage }) => {
14+
await importPage.gotoSimpleAIExerciseTimer();
15+
await importPage.expectOnPage();
16+
await importPage.expectName("Simple AI exercise timer");
17+
await importPage.startSession();
18+
19+
await dataSamplesPage.expectOnPage();
20+
await dataSamplesPage.expectActions(["exercising", "not exercising"]);
21+
});
22+
});

src/flags.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ export type Flag =
2020
* Flag to enable redux/zustand dev tools.
2121
*/
2222
| "devtools"
23+
/**
24+
* Flag to enable e2e support.
25+
*/
26+
| "e2e"
2327
/**
2428
* Flag to add a beta warning. Enabled for review and staging site stages.
2529
*/
@@ -52,6 +56,7 @@ const allFlags: FlagMetadata[] = [
5256
{ name: "exampleOptInA", defaultOnStages: ["review", "staging"] },
5357
{ name: "exampleOptInB", defaultOnStages: [] },
5458
{ name: "devtools", defaultOnStages: ["local"] },
59+
{ name: "e2e", defaultOnStages: [] },
5560
{
5661
name: "preReleaseNotice",
5762
defaultOnStages: ["staging"],

src/pages/ImportPage.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ const ImportPage = () => {
3838
const [params] = useSearchParams();
3939
setEditorVersionOverride(params.get("editorVersion") || undefined);
4040
const defaultProjectName = useDefaultProjectName();
41-
const [name, setName] = useState<string>(defaultProjectName);
41+
const [name, setName] = useState<string>(
42+
params.get("name") ?? defaultProjectName
43+
);
4244
const isValidSetup = validateProjectName(name);
4345
const [fetchingProject, setFetchingProject] = useState<boolean>(true);
4446
const [project, setProject] = useState<MakeCodeProject>();
@@ -63,7 +65,6 @@ const ImportPage = () => {
6365
intl
6466
);
6567
setProject(project);
66-
setName(resourceName ?? defaultProjectName);
6768
} catch (e) {
6869
// Log the fetch error, but fallback to new blank session by default.
6970
logging.error(e);
@@ -141,11 +142,12 @@ const ImportPage = () => {
141142
</Text>
142143
)}
143144
<Stack py={2} spacing={5}>
144-
<Heading size="md" as="h2">
145+
<Heading size="md" as="h2" id="name-label">
145146
<FormattedMessage id="name-text" />
146147
</Heading>
147148
<Input
148-
aria-labelledby={nameLabel}
149+
type="text"
150+
aria-labelledby="name-label"
149151
minW="25ch"
150152
value={name}
151153
name={nameLabel}

0 commit comments

Comments
 (0)