Skip to content

Commit

Permalink
Added tests to load the old XML and new JSON format in blockly worksp…
Browse files Browse the repository at this point in the history
…aces (#59)

* test: loading of old XML and new JSON files and saving to current file
  • Loading branch information
pajotg authored May 14, 2024
1 parent dee86d4 commit 7b8a879
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 0 deletions.
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;
}

0 comments on commit 7b8a879

Please sign in to comment.