Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added tests to load the old XML and new JSON format in blockly workspaces #59

Merged
merged 4 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions tests/load_workspace.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { expect, test } from "@playwright/test";
import { goToHomePage, mockShowOpenFilePicker } from "./utils";

test.beforeEach(goToHomePage);

let test_files = [
["Old Xml format", "hello_world_xml.l_original_uno"],
["New Json format", "hello_world_json.l_original_uno"],
];

for (let [testName, file] of test_files) {
test(`LoadAndSave - ${testName}`, async ({ page }) => {
await page.getByText("Leaphy Original").click();
await page.getByText("Original Uno").click();

await page.getByRole("button", { name: "My projects" }).click();

// Playwright doesn't seem to support `showOpenFilePicker()` so mock it
let createOnWritePromise = await mockShowOpenFilePicker(
page,
`./tests/saved_workspaces/${file}`,
);

await page.getByRole("cell", { name: "Open" }).click();

// All of these should be loaded in
await expect(page.getByText("repeat")).toBeVisible();
await expect(page.getByText("during")).toBeVisible();
await expect(page.getByText("hello world!")).toBeVisible();
await expect(page.getByText("10", { exact: true })).toBeVisible();

// The code should have also been updated
await page.locator(".side").first().click();

await expect(page.locator(".view-lines")).toContainText("test = 10");
await expect(page.locator(".view-lines")).toContainText("delay(1000)");
await expect(page.locator(".view-lines")).toContainText('"hello world!"');

// Save the project, it should write to the previously opened file!
await page.getByRole("button", { name: "My projects" }).click();

let onWritePromise = createOnWritePromise();
await page.getByRole("cell", { name: "Save", exact: true }).click();
let writtenChunks = await onWritePromise;
expect(JSON.stringify(writtenChunks)).toContain("hello world"); // This is very hacky, but it works
});
}
1 change: 1 addition & 0 deletions tests/saved_workspaces/hello_world_json.l_original_uno
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"blocks":{"languageVersion":0,"blocks":[{"type":"leaphy_start","id":"rzE0Ve:6bHB~8aIqyj-U","x":886,"y":100,"deletable":false,"inputs":{"STACK":{"block":{"type":"variables_set","id":"J6[_UnII$nn5;n-D7P3$","fields":{"VAR":{"id":"9s2~[Z2`R|0j/j@6xBGP"}},"inputs":{"VALUE":{"block":{"type":"math_number","id":"pdF9j#htw{Xs`Cu^4CI2","fields":{"NUM":10}}}},"next":{"block":{"type":"controls_whileUntil","id":"I9R6ZGCPgw]-=bxAdMW2","fields":{"MODE":"WHILE"},"inputs":{"BOOL":{"block":{"type":"logic_compare","id":"M8H2-TdeZobyf|`u2QlU","fields":{"OP":"GT"},"inputs":{"A":{"shadow":{"type":"math_number","id":"/r$j5]H,4+TNE5I@zVBa","fields":{"NUM":1}},"block":{"type":"variables_get","id":"HZPG$vIAV]RO4P(`nv}W","fields":{"VAR":{"id":"9s2~[Z2`R|0j/j@6xBGP"}}}},"B":{"shadow":{"type":"math_number","id":"XWy#p7-oQ,Os9e6JHa2u","fields":{"NUM":1}}}}}},"DO":{"block":{"type":"variables_set","id":"@?8QYZJK+f[LGj)z;)?+","fields":{"VAR":{"id":"9s2~[Z2`R|0j/j@6xBGP"}},"inputs":{"VALUE":{"block":{"type":"math_arithmetic","id":"SYvyhH*I*Anmq+l5SUnX","fields":{"OP":"MINUS"},"inputs":{"A":{"shadow":{"type":"math_number","id":"4%ey;V{RbJ^B4*oTmf|B","fields":{"NUM":1}},"block":{"type":"variables_get","id":"3i@X_D@WuUJ@3YTZ#-r~","fields":{"VAR":{"id":"9s2~[Z2`R|0j/j@6xBGP"}}}},"B":{"shadow":{"type":"math_number","id":"Q{EOVYZiEAvuv}a1.n22","fields":{"NUM":1}}}}}}},"next":{"block":{"type":"leaphy_serial_print_line","id":"ls|Kp5hrouDK:I3Uw]qK","inputs":{"VALUE":{"shadow":{"type":"text","id":"q,gPeGJ7wv.=tMi_F{sg","fields":{"TEXT":"hello world!"}}}},"next":{"block":{"type":"time_delay","id":"OS,gB$GEcY(30Z6YSaL6","inputs":{"DELAY_TIME_MILI":{"shadow":{"type":"math_number","id":"u*S`VE2z(@NFcD8zV{ZN","fields":{"NUM":1000}}}}}}}}}}}}}}}}}]},"variables":[{"name":"test","id":"9s2~[Z2`R|0j/j@6xBGP"}]}
81 changes: 81 additions & 0 deletions tests/saved_workspaces/hello_world_xml.l_original_uno
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<xml xmlns="https://developers.google.com/blockly/xml">
<variables>
<variable id="9s2~[Z2`R|0j/j@6xBGP">test</variable>
</variables>
<block type="leaphy_start" id="rzE0Ve:6bHB~8aIqyj-U" deletable="false" x="886" y="100">
<statement name="STACK">
<block type="variables_set" id="J6[_UnII$nn5;n-D7P3$">
<field name="VAR" id="9s2~[Z2`R|0j/j@6xBGP">test</field>
<value name="VALUE">
<block type="math_number" id="pdF9j#htw{Xs`Cu^4CI2">
<field name="NUM">10</field>
</block>
</value>
<next>
<block type="controls_whileUntil" id="I9R6ZGCPgw]-=bxAdMW2">
<field name="MODE">WHILE</field>
<value name="BOOL">
<block type="logic_compare" id="M8H2-TdeZobyf|`u2QlU">
<field name="OP">GT</field>
<value name="A">
<shadow type="math_number" id="/r$j5]H,4+TNE5I@zVBa">
<field name="NUM">1</field>
</shadow>
<block type="variables_get" id="HZPG$vIAV]RO4P(`nv}W">
<field name="VAR" id="9s2~[Z2`R|0j/j@6xBGP">test</field>
</block>
</value>
<value name="B">
<shadow type="math_number" id="XWy#p7-oQ,Os9e6JHa2u">
<field name="NUM">1</field>
</shadow>
</value>
</block>
</value>
<statement name="DO">
<block type="variables_set" id="@?8QYZJK+f[LGj)z;)?+">
<field name="VAR" id="9s2~[Z2`R|0j/j@6xBGP">test</field>
<value name="VALUE">
<block type="math_arithmetic" id="SYvyhH*I*Anmq+l5SUnX">
<field name="OP">MINUS</field>
<value name="A">
<shadow type="math_number" id="4%ey;V{RbJ^B4*oTmf|B">
<field name="NUM">1</field>
</shadow>
<block type="variables_get" id="3i@X_D@WuUJ@3YTZ#-r~">
<field name="VAR" id="9s2~[Z2`R|0j/j@6xBGP">test</field>
</block>
</value>
<value name="B">
<shadow type="math_number" id="Q{EOVYZiEAvuv}a1.n22">
<field name="NUM">1</field>
</shadow>
</value>
</block>
</value>
<next>
<block type="leaphy_serial_print_line" id="ls|Kp5hrouDK:I3Uw]qK">
<value name="VALUE">
<shadow type="text" id="q,gPeGJ7wv.=tMi_F{sg">
<field name="TEXT">hello world!</field>
</shadow>
</value>
<next>
<block type="time_delay" id="OS,gB$GEcY(30Z6YSaL6">
<value name="DELAY_TIME_MILI">
<shadow type="math_number" id="u*S`VE2z(@NFcD8zV{ZN">
<field name="NUM">1000</field>
</shadow>
</value>
</block>
</next>
</block>
</next>
</block>
</statement>
</block>
</next>
</block>
</statement>
</block>
</xml>
61 changes: 61 additions & 0 deletions tests/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { promises as fs } from "node:fs";
import type { Page, PlaywrightTestArgs } from "@playwright/test";

export async function goToHomePage({ page }: PlaywrightTestArgs) {
Expand All @@ -11,3 +12,63 @@ export async function openExample(page: Page, example: string | RegExp) {
await page.getByRole("cell", { name: "Examples" }).click();
await page.getByRole("button", { name: example }).click();
}

// Playwright doesn't seem to support `showOpenFilePicker()` so this functions mocks it
export async function mockShowOpenFilePicker(
page: Page,
path: string,
): Promise<Promise<(timeout?: number) => Promise<FileSystemWriteChunkType[]>>> {
let content = await fs.readFile(path, "utf-8");

await page.evaluate(
([content, path]) => {
const blob = new Blob([content], { type: "application/json" });
const file = new File([blob], path, { type: "application/json" });

const createWritable = async () => {
let writtenChunks: FileSystemWriteChunkType[] = [];
return {
write: async (data: FileSystemWriteChunkType) => {
writtenChunks.push(data);
},
close: async () => {
await (window as any).onWriteOpenedFile(writtenChunks);
},
};
};

const fileHandle = {
getFile: async () => file,
name: path,
createWritable,
};

(window as any).showOpenFilePicker = async () => {
return [fileHandle];
};
},
[content, path],
);

let createOnWritePromise = async (timeout = 1000) => {
let onWriteResolve:
| ((writtenChunks: FileSystemWriteChunkType[]) => void)
| undefined = undefined;

await page.exposeFunction(
"onWriteOpenedFile",
(writtenChunks: FileSystemWriteChunkType[]) => {
if (onWriteResolve) onWriteResolve(writtenChunks);
},
);

return new Promise<FileSystemWriteChunkType[]>((resolve, reject) => {
onWriteResolve = resolve;
setTimeout(() => {
reject("File not written within time!");
}, timeout);
});
};

return createOnWritePromise;
}