diff --git a/README.md b/README.md
index 900089383e..7798ed9929 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ A [feature-rich](https://livecodes.io/docs/features/), open-source, **client-sid
[](https://www.npmjs.com/package/livecodes)
[](https://www.npmjs.com/package/livecodes)
[](https://www.jsdelivr.com/package/npm/livecodes)
-[](https://livecodes.io/docs/languages/)
+[](https://livecodes.io/docs/languages/)
[](https://livecodes.io/docs/)
[](https://livecodes.io/docs/llms.txt)
[](https://livecodes.io/docs/llms-full.txt)
diff --git a/docs/docs/languages/go-wasm.mdx b/docs/docs/languages/go-wasm.mdx
new file mode 100644
index 0000000000..1f8c108758
--- /dev/null
+++ b/docs/docs/languages/go-wasm.mdx
@@ -0,0 +1,93 @@
+# Go (Wasm)
+
+[Go](https://go.dev/) (Golang), is an open-source, statically typed, and compiled programming language developed by Google. It is designed for simplicity, efficiency, and strong support for concurrency, making it well-suited for building scalable and high-performance applications.
+
+LiveCodes uses [Yaegi](https://github.com/traefik/yaegi), the Go interpreter (running on WebAssembly), to run Go in the browser.
+
+:::info Note
+
+LiveCodes also supports running Go using [GopherJS](https://github.com/gopherjs/gopherjs) which is a Go to JavaScript compiler. Read documentation [here](./go.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const params = {
+ 'go-wasm': 'package main\n\nimport "fmt"\n\nfunc main() {\n\tfmt.Println("Hello, World!")\n}\n',
+ console: 'full',
+};
+
+
+
+## Usage
+
+LiveCodes runs Go in the browser, including the [standard library](https://pkg.go.dev/std).
+
+
+### Communication with JavaScript
+
+The Go code runs in the context of the [result page](../features/result.mdx).
+A few helper properties and methods are available in the browser global `livecodes.goWasm` object:
+
+- `livecodes.goWasm.input`: the initial standard input that is passed to the Go code.
+- `livecodes.goWasm.loaded`: A promise that resolves when the Go environment is loaded. Any other helpers should be used after this promise resolves.
+- `livecodes.goWasm.output`: the standard output.
+- `livecodes.goWasm.error`: the standard error.
+- `livecodes.goWasm.exitCode`: the exit code.
+- `livecodes.goWasm.run`: a function that runs the Go code with new input. This function takes a string as input and returns a promise that resolves when the Go code is done running. The promise resolves with an object containing the `input`, `output`, `error`, and `exitCode` properties.
+
+See the [example below](#example-usage) for more details.
+
+## Language Info
+
+### Name
+
+`go-wasm`
+
+### Extensions
+
+`wasm.go`, `go-wasm`, `gowasm`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[Yaegi](https://github.com/traefik/yaegi), compiled to WebAssembly ([yaegi-wasm](https://github.com/Muhammad-Ayman/yaegi-wasm))
+
+### Version
+
+Yaegi v0.16.1, running go1.25.0
+
+## Code Formatting
+
+Using [GopherJS](https://github.com/gopherjs/gopherjs)
+
+## Example Usage
+
+This example demonstrates standard library usage and JavaScript interoperability (also check the code in the HTML editor):
+
+
+
+
+## Live Reload
+
+By default, new code changes are sent to the result page for re-evaluation without a full page reload, to avoid the need to reload the Go environment.
+
+This behavior can be disabled by adding the code comment `// __livecodes_reload__` to the code, which will force a full page reload.
+This comment can be added in the [`hiddenContent` property of the editor](../configuration/configuration-object.mdx#markup) for embedded playgrounds.
+
+## Starter Template
+
+https://livecodes.io/?template=go-wasm
+
+## Links
+
+- [Go](https://go.dev/)
+- [Go documentation](https://go.dev/doc/)
+- [Go standard library](https://pkg.go.dev/std)
+- [Yaegi](https://github.com/traefik/yaegi)
+- [Go using GopherJS](./go.mdx) in LiveCodes
diff --git a/docs/docs/languages/go.mdx b/docs/docs/languages/go.mdx
index 2e71b7f967..e3a584e872 100644
--- a/docs/docs/languages/go.mdx
+++ b/docs/docs/languages/go.mdx
@@ -1,3 +1,72 @@
# Go (Golang)
-TODO...
+[Go](https://go.dev/) (Golang), is an open-source, statically typed, and compiled programming language developed by Google. It is designed for simplicity, efficiency, and strong support for concurrency, making it well-suited for building scalable and high-performance applications.
+
+LiveCodes uses [GopherJS](https://github.com/gopherjs/gopherjs) which is a Go to JavaScript compiler, to run Go in the browser.
+
+:::info Note
+
+LiveCodes also supports running Go using [Yaegi](https://github.com/traefik/yaegi), the Go interpreter (running on WebAssembly). Read documentation [here](./go-wasm.mdx).
+
+:::
+
+## Demo
+
+import LiveCodes from '../../src/components/LiveCodes.tsx';
+
+export const params = {
+ 'go': 'package main\n\nimport "fmt"\n\nfunc main() {\n\tfmt.Println("Hello, World!")\n}\n',
+ console: 'full',
+};
+
+
+
+## Usage
+
+LiveCodes runs Go in the browser, including the [standard library](https://pkg.go.dev/std).
+
+JavaScript interoperability and DOM access is achieved using [package `js`](https://pkg.go.dev/syscall/js) (see the [example below](#example-usage)).
+
+## Language Info
+
+### Name
+
+`go`
+
+### Extensions
+
+`go`, `golang`
+
+### Editor
+
+`script`
+
+## Compiler
+
+[GopherJS](https://github.com/gopherjs/gopherjs), the Go to JavaScript compiler.
+
+### Version
+
+GopherJS v1.19.0 beta1, running Go 1.19.13
+
+## Code Formatting
+
+Using [GopherJS](https://github.com/gopherjs/gopherjs)
+
+## Example Usage
+
+This example demonstrates standard library usage, JavaScript interoperability and DOM access:
+
+
+
+## Starter Template
+
+https://livecodes.io/?template=go
+
+## Links
+
+- [Go](https://go.dev/)
+- [Go documentation](https://go.dev/doc/)
+- [Go standard library](https://pkg.go.dev/std)
+- [GopherJS](https://github.com/gopherjs/gopherjs)
+- [Go using Yaegi](./go-wasm.mdx) in LiveCodes
diff --git a/docs/src/components/LanguageSliders.tsx b/docs/src/components/LanguageSliders.tsx
index e1daff5ac6..960c4933a6 100644
--- a/docs/src/components/LanguageSliders.tsx
+++ b/docs/src/components/LanguageSliders.tsx
@@ -83,6 +83,7 @@ export default function Sliders() {
{ name: 'ruby', title: 'Ruby' },
{ name: 'ruby-wasm', title: 'Ruby (Wasm)' },
{ name: 'go', title: 'Go' },
+ { name: 'go-wasm', title: 'Go (Wasm)' },
{ name: 'php', title: 'PHP' },
{ name: 'php-wasm', title: 'PHP (Wasm)' },
{ name: 'cpp', title: 'C++' },
diff --git a/docs/src/components/TemplateList.tsx b/docs/src/components/TemplateList.tsx
index 126f377f72..a246d4d47a 100644
--- a/docs/src/components/TemplateList.tsx
+++ b/docs/src/components/TemplateList.tsx
@@ -42,6 +42,7 @@ const templates = [
{ name: 'ruby', title: 'Ruby Starter', thumbnail: 'ruby.svg' },
{ name: 'ruby-wasm', title: 'Ruby (Wasm) Starter', thumbnail: 'ruby.svg' },
{ name: 'go', title: 'Go Starter', thumbnail: 'go.svg' },
+ { name: 'go-wasm', title: 'Go (Wasm) Starter', thumbnail: 'go.svg' },
{ name: 'php', title: 'PHP Starter', thumbnail: 'php.svg' },
{ name: 'php-wasm', title: 'PHP (Wasm) Starter', thumbnail: 'php.svg' },
{ name: 'cpp', title: 'C++ Starter', thumbnail: 'cpp.svg' },
diff --git a/e2e/specs/compilers.spec.ts b/e2e/specs/compilers.spec.ts
index bba6112526..d18dd75263 100644
--- a/e2e/specs/compilers.spec.ts
+++ b/e2e/specs/compilers.spec.ts
@@ -1,1783 +1,1783 @@
-import { expect } from '@playwright/test';
-import { getLoadedApp, waitForEditorFocus } from '../helpers';
-import { test } from '../test-fixtures';
-
-test.describe('Compiler Results', () => {
- test('HTML/CSS/JS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.type('hello, ');
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text="CSS"');
- await waitForEditorFocus(app);
- await page.keyboard.type('body {color: blue;}');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="JavaScript"');
- await waitForEditorFocus(app);
- await page.keyboard.type('document.body.innerHTML += "world!"');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('body');
-
- expect(resultText).toContain('hello, world!');
- expect(await getResult().$eval('body', (e) => getComputedStyle(e).color)).toBe(
- 'rgb(0, 0, 255)',
- );
- });
-
- test('Markdown', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Markdown');
- await waitForEditorFocus(app);
- await app.page().keyboard.type('# Hi There');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hi There');
- });
-
- test('MDX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=MDX');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`
-import {Hello} from './script';
-
-
-`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JSX');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`
-import React from 'react';
-export const Hello = (props) =>
Hello, {props.title}! ;
-`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hello, World!');
- });
-
- test('Astro', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Astro');
- await waitForEditorFocus(app);
- await app.page().keyboard.type(`---
-const title = "World";
----
-
-Hello, {title}! `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hello, World!');
- });
-
- test('Pug', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Pug');
- await waitForEditorFocus(app);
- await page.keyboard.type('h1 Hi There');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toBe('Hi There');
- });
-
- test('Haml', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Haml"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Haml"');
- await waitForEditorFocus(app);
- await page.keyboard.type('.content Hello, #{name}!');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('.content');
-
- expect(resultText).toContain('Hello, Haml!');
- });
-
- test('AsciiDoc', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=AsciiDoc');
- await waitForEditorFocus(app);
- await page.keyboard.type('== Hello, World!');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h2');
-
- expect(resultText).toContain('Hello, World!');
- });
-
- test('Mustache', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Mustache"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Mustache');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Mustache');
- });
-
- test('Mustache dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Mustache' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Mustache');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Mustache');
- });
-
- test('Handlebars', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Handlebars"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Handlebars');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Handlebars');
- });
-
- test('Handlebars dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Handlebars' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Handlebars');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Handlebars');
- });
-
- test('Nunjucks', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Nunjucks"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Nunjucks');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Nunjucks');
- });
-
- test('Nunjucks dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Nunjucks' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Nunjucks');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Nunjucks');
- });
-
- test('EJS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "EJS"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=EJS');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= name %> `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to EJS');
- });
-
- test('EJS dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'EJS' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=EJS');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= name %> `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to EJS');
- });
-
- test('Eta', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Eta"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Eta"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= it.name %> `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Eta');
- });
-
- test('Eta dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Eta' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Eta"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to <%= it.name %> `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Eta');
- });
-
- test('Liquid', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name":"liquid"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Liquid');
- await waitForEditorFocus(app);
- await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
-
- await waitForResultUpdate();
- const body = await getResult().$('body');
-
- expect(await body?.innerHTML()).toContain('Welcome to Liquid');
- });
-
- test('Liquid dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'liquid' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Liquid');
- await waitForEditorFocus(app);
- await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const body = await getResult().$('body');
-
- expect(await body?.innerHTML()).toContain('Welcome to Liquid');
- });
-
- test('doT', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name":"doT"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=doT');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{=it.name}} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to doT');
- });
-
- test('doT dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'doT' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=doT');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{=it.name}} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to doT');
- });
-
- test('Twig', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Twig"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Twig');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Twig');
- });
-
- test('Twig dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Twig' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Twig');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Twig');
- });
-
- test('Vento', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "Vento"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Vento');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Vento');
- });
-
- test('Vento dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'Vento' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=Vento');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to Vento');
- });
-
- test('art-template', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "art-template"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=art-template');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to art-template');
- });
-
- test('art-template dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'art-template' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=art-template');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to art-template');
- });
-
- test('jinja', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"data":{"name": "jinja"}}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Jinja"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to jinja');
- });
-
- test('jinja dynamic', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('[aria-label="Project"]');
- await app.click('text=Custom Settings');
- await waitForEditorFocus(app, '#custom-settings-editor');
- await page.keyboard.press('Control+A');
- await page.keyboard.press('Delete');
- await page.keyboard.type(`{"template":{"prerender": false}}`);
- await app.click('button:has-text("Load"):visible');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=JavaScript');
- await waitForEditorFocus(app);
- await page.keyboard.type(`window.livecodes.templateData = { name: 'jinja' };`);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text="Jinja"');
- await waitForEditorFocus(app);
- await page.keyboard.type(`Welcome to {{ name }} `);
-
- await waitForResultUpdate();
- await app.waitForTimeout(3000);
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain('Welcome to jinja');
- });
-
- test('BBCode', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=BBCode');
- await waitForEditorFocus(app);
- await app.page().keyboard.type('[quote]quoted text[/quote]');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('blockquote');
-
- expect(resultText).toBe('quoted text');
- });
-
- test('MJML', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 1)');
- await app.click('text=MJML');
- await waitForEditorFocus(app);
- await page.keyboard.type(`
-
-
-
-
-
- Hello MJML!
-
-
-
-
-
-`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('table');
-
- expect(resultText).toContain('Hello MJML!');
- });
-
- test('SCSS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=SCSS');
- await waitForEditorFocus(app);
- await page.keyboard.type(
- `$font-stack: Helvetica, sans-serif; body { font: 100% $font-stack; }`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
- });
-
- test('Sass', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Sass');
- await waitForEditorFocus(app);
- await page.keyboard.type(`$font-stack: Helvetica, sans-serif\nbody\n font: 100% $font-stack`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
- });
-
- test('Less', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Less');
- await waitForEditorFocus(app);
- await page.keyboard.type(`@width: 10px; #header { width: @width; }`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('width: 10px;');
- });
-
- test('Stylus', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Stylus');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`font-size = 14px\nbody\n font font-size Arial, sans-serif`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('font: 14px Arial, sans-serif;');
- });
-
- test('Stylis', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Stylis');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- '[namespace] {\n div {\n display: flex;\n\n @media screen {\n color: blue;\n }\n }\n\n div {\n transform: translateZ(0);\n\n h1, h2 {\n color: red;\n }\n }\n}',
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain(
- '[namespace] div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}@media screen{[namespace] div{color:blue;}}[namespace] div{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);}[namespace] div h1,[namespace] div h2{color:red;}',
- );
- });
-
- test('PostCSS/postcssImportUrl', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Import Url');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`@import "github-markdown-css";`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('.markdown-body');
- });
-
- test('PostCSS/Autoprefixer', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Autoprefixer');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`.example { user-select: none; }`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('-webkit-user-select: none;');
- });
-
- test('PostCSS/Preset Env', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Preset Env');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `:root { --mainColor: #12345678; --secondaryColor: lab(32.5 38.5 -47.6 / 90%); }`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('style');
-
- expect(resultText).toContain('--mainColor: rgba(18,52,86,0.47059);');
- });
-
- test('Babel', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Babel');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`[1, 2, 3].map(n => n + 1);`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `[1, 2, 3].map(function (n) {
- return n + 1;
-});`,
- );
- });
-
- test('Sucrase', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Sucrase');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`const Greet = (name: string) => <>Hello {name}!>;`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `const Greet = (name) => React.createElement(React.Fragment, null, "Hello " , name, "!");`,
- );
- });
-
- test('TypeScript', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=TypeScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `type Fish = { swim: () => void };
-type Bird = { fly: () => void };
-declare function getSmallPet(): Fish | Bird;
-// ---cut---
-function isFish(pet: Fish | Bird): pet is Fish {
- return (pet as Fish).swim !== undefined;
-}`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- `// ---cut---
-function isFish(pet) {
- return pet.swim !== undefined;
-}`,
- );
- });
-
- test('Flow', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Flow');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- 'function foo(x: ?number): string {if (x) { return x; } return "default string"; }',
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(
- 'function foo(x ) {if (x) { return x; } return "default string"; }',
- );
- });
-
- test('JSX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`Loading...
`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="JSX"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-const Hello = (props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('TSX', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="TSX"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-interface Props { name: string }
-const Hello = (props: Props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('React', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`Loading...
`);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="React"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-const Hello = (props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('React (TSX)', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text="React (TSX)"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-interface Props { name: string }
-const Hello = (props: Props) => Hello, {props.name}
-export default () => ;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, React`);
- });
-
- test('Vue', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-Hello, {{ title }}
-
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Vue`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Vue JSX', async ({ page, getTestUrl }) => {
- const sfc = `
-
-
-`;
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- await getResult().click('text=Click me');
- await getResult().click('text=Click me');
- await getResult().click('text=Click me');
-
- const titleText = await getResult().innerText('h1');
- expect(titleText).toBe('Hello, Vue!');
-
- const counterText = await getResult().innerText('text=You clicked');
- expect(counterText).toBe('You clicked 3 times.');
- });
-
- test('Vue import', async ({ page, getTestUrl }) => {
- const sfc = `
-
-
-
-
-`;
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- // css import
- const headHTML = await getResult().innerHTML('head');
- expect(headHTML).toContain(
- ' ',
- );
-
- // bare module import
- const uuidText = await getResult().innerText('#uuid');
- expect(uuidText.length).toBeGreaterThan(10);
-
- // import vue component
- await getResult().click(':nth-match(button, 1)');
- await getResult().click(':nth-match(button, 1)');
- await getResult().click(':nth-match(button, 1)');
-
- // import vue component that has relative imports and fetches absolute url
- const buttonText = await getResult().innerText(':nth-match(button, 1)');
- expect(buttonText).toBe('Count is: 3, double is: 6');
- });
-
- test('Vue langs', async ({ page, getTestUrl }) => {
- const sfc = `
- # Hello, {{ name }}!
- some text
-
-
-
-
-
-`;
-
- await page.goto(
- getTestUrl({
- x: 'code/N4IgLglmA2CmIC4QFUB2kawCYAIAKATgPYBWsAxmCADQhawDO5BEADpEaoiDeAIYBzBogDaAXVp9KEAG6wAolihEC3Ji3a8AtnwIBrAK6tEoaH1QCDg+EgAWYLdF7lOYWOm4gAvrQZgAnnAmIGYWVgI2IOQMwrQu6O5USN6+zGxJpuaW1twyBvBxroncADxuWqxmbjihAgC8ADogWlhNAHwNBA2oODgAxDgAErDQ0ETUOMDAOKh8WrA4Xl4AhJ3dvSWsOAjkZjGNIAAkfoGwAHRuAB5g7QxE8zhXYCUA9KwdXaiv5ZV8bh-dNZfdTpGpZA5gBhNHAMWBgIwAno4eJ+GZzWAIGFgFgWHB1HAAcgAavkcABmAkAbiBrxB7ERNJOcDBFgOTBi0K0RCwBjgiN6hwAZq4ALR+KR6THDaBySDkPgTBjmBhi2AsQXUz4C1gsHQEfwilxjAiYvoAVgtmvWOGOFE4WF0BqNKkxAgIsHcVtQQN6tgAjJMfb0cML0JiAEwABkjAFIbaGwGKwBKvcHkURjZjDjqIHqnRmVKnFkCgxdYNdA1rgwnMX7o3GhaLxeQ9EXes6TTbYfEHfrDQWCEWvDSXkzYG0UiAxwxbB7IaIJFO0uxhAhxHEYoRGHDPLQdURyIw7gRV+uogY-PcAMpwyAWVfAHwgXOsFTzhCP2gBViMExPtx+A+IRZOEkTfowy5UIUCQeMkT5yCeECcNwAAs3hAA',
- }),
- );
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- // await page.keyboard.insertText(sfc);
-
- await waitForResultUpdate();
-
- const headerText = await getResult().innerText('h1');
-
- // markdown, scss, typescript
- expect(headerText).toContain(`Hello, Vue 3!`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(85, 85, 85)');
-
- // css modules
- expect(await getResult().$eval('p', (e) => getComputedStyle(e).color)).toBe('rgb(0, 128, 0)');
- });
-
- test('Vue + Tailwind CSS', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="vue"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
Tailwind in Vue SFC
-
-
-`,
- );
-
- await app.click(':nth-match([title="Change Language"], 2)');
- await app.click('text=Tailwind CSS');
- await app.click('text=CSS');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `@tailwind base;
-@tailwind components;
-@tailwind utilities;
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Tailwind in Vue SFC`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe(
- 'rgb(220, 38, 38)',
- );
- });
-
- test('Vue 2', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Vue 2');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-Hello, {{ title }}
-
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Vue 2`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Svelte', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await (await app.$('[data-lang="svelte"]'))?.click();
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
-
Hello, {title}
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Svelte`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Malina.js', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Malina.js');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `
-
-
-
Hello, {title}
-
-`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Malina.js`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('Stencil', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(' ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Stencil');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `import { Component, Prop, h } from "@stencil/core";
-@Component({
- tag: "my-app",
- styles: "h1 { color: blue; }",
-})
-export class App {
- @Prop() title: string;
- render() {
- return (
- Hello, {this.title}
- );
- }
-}`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('h1');
-
- expect(resultText).toContain(`Hello, Stencil`);
- expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
- });
-
- test('CoffeeScript', async ({ page, getTestUrl }) => {
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=CoffeeScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`square = (x) -> x * x`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerHTML('body > script');
-
- expect(resultText).toContain(`var square;`);
- expect(resultText).toContain(`square = function(x) {
- return x * x;
-};`);
- });
-
- test('LiveScript', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, World ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=LiveScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`{ capitalize, join, map, words } = require 'prelude-ls'
-title = 'live script'
-|> words
-|> map capitalize
-|> join ''
-(document.getElementById \\title).textContent = title`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, LiveScript`);
- });
-
- test('Riot.js', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(' ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Riot.js');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, {props.title} ');
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Riot.js`);
- });
-
- test('AssemblyScript', async ({ page, getTestUrl }) => {
- test.fixme();
-
- await page.goto(getTestUrl());
-
- const { app, getResult } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(
- `Hello, World
- `,
- );
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=AssemblyScript');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`export function getTitle(): string {return "AssemblyScript";`);
- // workaround for monaco auto-complete
- await page.keyboard.press('Delete');
- await page.keyboard.insertText(`}`);
-
- await app.waitForTimeout(15000);
- const resultText = await getResult().innerText('text=Hello, AssemblyScript');
-
- expect(resultText).toContain(`Hello, AssemblyScript`);
- });
-
- test('Python', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Python');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`from browser import document
-title = 'Python'
-document['header'].html = f"Hello, {title}"`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Python`);
- });
-
- test('Pyodide', async ({ page, getTestUrl }) => {
- test.skip();
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Pyodide');
- await waitForEditorFocus(app);
- await page.keyboard.insertText(`from js import document
-title = 'Python'
-document.getElementById('header').innerHTML = f"Hello, {title}"`);
-
- await waitForResultUpdate();
- await getResult().waitForSelector('text=Hello, Python');
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Python`);
- });
-
- test('Ruby', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Ruby');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`require "native"
-title = 'Ruby'
-$$.document.querySelector('#title').innerHTML = title`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('text=Hello, Ruby');
-
- expect(resultText).toContain(`Hello, Ruby`);
- });
-
- test('Go', async ({ page, getTestUrl, editor }) => {
- test.slow();
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Go');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`package main
-import "syscall/js"
-func main() {
- js.Global().Get("document").Call("querySelector", "#title").Set("innerHTML", "Golang")
-}`);
-
- await waitForResultUpdate({ delay: 4000, timeout: 60_000 });
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Golang`);
- });
-
- test('PHP', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=PHP');
- await waitForEditorFocus(app);
-
- // go below pre-inserted 'getElementById('title')->textContent = $title;`,
- );
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, PHP`);
- });
-
- test('Perl', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Perl');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`use strict;
-my $title = 'Perl';
-JS::inline('document.getElementById("title").innerHTML') = $title;`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Perl`);
- });
-
- test('Lua', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Lua');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`js = require "js"
-window = js.global
-document = window.document
-document:getElementById("title").innerHTML = "Lua"`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Lua`);
- });
-
- test('Scheme', async ({ page, getTestUrl, editor }) => {
- test.skip(editor === 'codejar', 'please fix');
-
- await page.goto(getTestUrl());
-
- const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
-
- await app.click('text="HTML"');
- await waitForEditorFocus(app);
- await page.keyboard.insertText('Hello, world ');
-
- await app.click(':nth-match([title="Change Language"], 3)');
- await app.click('text=Scheme');
- await waitForEditorFocus(app);
-
- await page.keyboard.insertText(`(let ((title "Scheme"))
- (set-content! "#title" title))`);
-
- await waitForResultUpdate();
- const resultText = await getResult().innerText('h1');
-
- expect(resultText).toContain(`Hello, Scheme`);
- });
-});
+import { expect } from '@playwright/test';
+import { getLoadedApp, waitForEditorFocus } from '../helpers';
+import { test } from '../test-fixtures';
+
+test.describe('Compiler Results', () => {
+ test('HTML/CSS/JS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('hello, ');
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text="CSS"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('body {color: blue;}');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="JavaScript"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('document.body.innerHTML += "world!"');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('body');
+
+ expect(resultText).toContain('hello, world!');
+ expect(await getResult().$eval('body', (e) => getComputedStyle(e).color)).toBe(
+ 'rgb(0, 0, 255)',
+ );
+ });
+
+ test('Markdown', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Markdown');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type('# Hi There');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hi There');
+ });
+
+ test('MDX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=MDX');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`
+import {Hello} from './script';
+
+
+`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JSX');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`
+import React from 'react';
+export const Hello = (props) => Hello, {props.title}! ;
+`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hello, World!');
+ });
+
+ test('Astro', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Astro');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type(`---
+const title = "World";
+---
+
+Hello, {title}! `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hello, World!');
+ });
+
+ test('Pug', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Pug');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('h1 Hi There');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toBe('Hi There');
+ });
+
+ test('Haml', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Haml"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Haml"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('.content Hello, #{name}!');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('.content');
+
+ expect(resultText).toContain('Hello, Haml!');
+ });
+
+ test('AsciiDoc', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=AsciiDoc');
+ await waitForEditorFocus(app);
+ await page.keyboard.type('== Hello, World!');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h2');
+
+ expect(resultText).toContain('Hello, World!');
+ });
+
+ test('Mustache', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Mustache"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Mustache');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Mustache');
+ });
+
+ test('Mustache dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Mustache' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Mustache');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Mustache');
+ });
+
+ test('Handlebars', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Handlebars"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Handlebars');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Handlebars');
+ });
+
+ test('Handlebars dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Handlebars' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Handlebars');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Handlebars');
+ });
+
+ test('Nunjucks', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Nunjucks"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Nunjucks');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Nunjucks');
+ });
+
+ test('Nunjucks dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Nunjucks' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Nunjucks');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Nunjucks');
+ });
+
+ test('EJS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "EJS"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=EJS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= name %> `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to EJS');
+ });
+
+ test('EJS dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'EJS' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=EJS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= name %> `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to EJS');
+ });
+
+ test('Eta', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Eta"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Eta"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= it.name %> `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Eta');
+ });
+
+ test('Eta dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Eta' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Eta"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to <%= it.name %> `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Eta');
+ });
+
+ test('Liquid', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name":"liquid"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Liquid');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
+
+ await waitForResultUpdate();
+ const body = await getResult().$('body');
+
+ expect(await body?.innerHTML()).toContain('Welcome to Liquid');
+ });
+
+ test('Liquid dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'liquid' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Liquid');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`{{ name | capitalize | prepend: "Welcome to "}}`);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const body = await getResult().$('body');
+
+ expect(await body?.innerHTML()).toContain('Welcome to Liquid');
+ });
+
+ test('doT', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name":"doT"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=doT');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{=it.name}} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to doT');
+ });
+
+ test('doT dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'doT' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=doT');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{=it.name}} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to doT');
+ });
+
+ test('Twig', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Twig"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Twig');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Twig');
+ });
+
+ test('Twig dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Twig' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Twig');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Twig');
+ });
+
+ test('Vento', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "Vento"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Vento');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Vento');
+ });
+
+ test('Vento dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'Vento' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=Vento');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to Vento');
+ });
+
+ test('art-template', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "art-template"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=art-template');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to art-template');
+ });
+
+ test('art-template dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'art-template' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=art-template');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to art-template');
+ });
+
+ test('jinja', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"data":{"name": "jinja"}}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Jinja"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to jinja');
+ });
+
+ test('jinja dynamic', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('[aria-label="Project"]');
+ await app.click('text=Custom Settings');
+ await waitForEditorFocus(app, '#custom-settings-editor');
+ await page.keyboard.press('Control+A');
+ await page.keyboard.press('Delete');
+ await page.keyboard.type(`{"template":{"prerender": false}}`);
+ await app.click('button:has-text("Load"):visible');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=JavaScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`window.livecodes.templateData = { name: 'jinja' };`);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text="Jinja"');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`Welcome to {{ name }} `);
+
+ await waitForResultUpdate();
+ await app.waitForTimeout(3000);
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain('Welcome to jinja');
+ });
+
+ test('BBCode', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=BBCode');
+ await waitForEditorFocus(app);
+ await app.page().keyboard.type('[quote]quoted text[/quote]');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('blockquote');
+
+ expect(resultText).toBe('quoted text');
+ });
+
+ test('MJML', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 1)');
+ await app.click('text=MJML');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`
+
+
+
+
+
+ Hello MJML!
+
+
+
+
+
+`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('table');
+
+ expect(resultText).toContain('Hello MJML!');
+ });
+
+ test('SCSS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=SCSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(
+ `$font-stack: Helvetica, sans-serif; body { font: 100% $font-stack; }`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
+ });
+
+ test('Sass', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Sass');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`$font-stack: Helvetica, sans-serif\nbody\n font: 100% $font-stack`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 100% Helvetica, sans-serif;');
+ });
+
+ test('Less', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Less');
+ await waitForEditorFocus(app);
+ await page.keyboard.type(`@width: 10px; #header { width: @width; }`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('width: 10px;');
+ });
+
+ test('Stylus', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Stylus');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`font-size = 14px\nbody\n font font-size Arial, sans-serif`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('font: 14px Arial, sans-serif;');
+ });
+
+ test('Stylis', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Stylis');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ '[namespace] {\n div {\n display: flex;\n\n @media screen {\n color: blue;\n }\n }\n\n div {\n transform: translateZ(0);\n\n h1, h2 {\n color: red;\n }\n }\n}',
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain(
+ '[namespace] div{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}@media screen{[namespace] div{color:blue;}}[namespace] div{-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);}[namespace] div h1,[namespace] div h2{color:red;}',
+ );
+ });
+
+ test('PostCSS/postcssImportUrl', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Import Url');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`@import "github-markdown-css";`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('.markdown-body');
+ });
+
+ test('PostCSS/Autoprefixer', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Autoprefixer');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`.example { user-select: none; }`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('-webkit-user-select: none;');
+ });
+
+ test('PostCSS/Preset Env', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Preset Env');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `:root { --mainColor: #12345678; --secondaryColor: lab(32.5 38.5 -47.6 / 90%); }`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('style');
+
+ expect(resultText).toContain('--mainColor: rgba(18,52,86,0.47059);');
+ });
+
+ test('Babel', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Babel');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`[1, 2, 3].map(n => n + 1);`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `[1, 2, 3].map(function (n) {
+ return n + 1;
+});`,
+ );
+ });
+
+ test('Sucrase', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Sucrase');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`const Greet = (name: string) => <>Hello {name}!>;`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `const Greet = (name) => React.createElement(React.Fragment, null, "Hello " , name, "!");`,
+ );
+ });
+
+ test('TypeScript', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=TypeScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `type Fish = { swim: () => void };
+type Bird = { fly: () => void };
+declare function getSmallPet(): Fish | Bird;
+// ---cut---
+function isFish(pet: Fish | Bird): pet is Fish {
+ return (pet as Fish).swim !== undefined;
+}`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ `// ---cut---
+function isFish(pet) {
+ return pet.swim !== undefined;
+}`,
+ );
+ });
+
+ test('Flow', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Flow');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ 'function foo(x: ?number): string {if (x) { return x; } return "default string"; }',
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(
+ 'function foo(x ) {if (x) { return x; } return "default string"; }',
+ );
+ });
+
+ test('JSX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`Loading...
`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="JSX"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+const Hello = (props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('TSX', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="TSX"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+interface Props { name: string }
+const Hello = (props: Props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('React', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`Loading...
`);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="React"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+const Hello = (props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('React (TSX)', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text="React (TSX)"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+interface Props { name: string }
+const Hello = (props: Props) => Hello, {props.name}
+export default () => ;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, React`);
+ });
+
+ test('Vue', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+Hello, {{ title }}
+
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Vue`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Vue JSX', async ({ page, getTestUrl }) => {
+ const sfc = `
+
+
+`;
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+ await getResult().click('text=Click me');
+
+ const titleText = await getResult().innerText('h1');
+ expect(titleText).toBe('Hello, Vue!');
+
+ const counterText = await getResult().innerText('text=You clicked');
+ expect(counterText).toBe('You clicked 3 times.');
+ });
+
+ test('Vue import', async ({ page, getTestUrl }) => {
+ const sfc = `
+
+
+
+
+`;
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ // css import
+ const headHTML = await getResult().innerHTML('head');
+ expect(headHTML).toContain(
+ ' ',
+ );
+
+ // bare module import
+ const uuidText = await getResult().innerText('#uuid');
+ expect(uuidText.length).toBeGreaterThan(10);
+
+ // import vue component
+ await getResult().click(':nth-match(button, 1)');
+ await getResult().click(':nth-match(button, 1)');
+ await getResult().click(':nth-match(button, 1)');
+
+ // import vue component that has relative imports and fetches absolute url
+ const buttonText = await getResult().innerText(':nth-match(button, 1)');
+ expect(buttonText).toBe('Count is: 3, double is: 6');
+ });
+
+ test('Vue langs', async ({ page, getTestUrl }) => {
+ const sfc = `
+ # Hello, {{ name }}!
+ some text
+
+
+
+
+
+`;
+
+ await page.goto(
+ getTestUrl({
+ x: 'code/N4IgLglmA2CmIC4QFUB2kawCYAIAKATgPYBWsAxmCADQhawDO5BEADpEaoiDeAIYBzBogDaAXVp9KEAG6wAolihEC3Ji3a8AtnwIBrAK6tEoaH1QCDg+EgAWYLdF7lOYWOm4gAvrQZgAnnAmIGYWVgI2IOQMwrQu6O5USN6+zGxJpuaW1twyBvBxroncADxuWqxmbjihAgC8ADogWlhNAHwNBA2oODgAxDgAErDQ0ETUOMDAOKh8WrA4Xl4AhJ3dvSWsOAjkZjGNIAAkfoGwAHRuAB5g7QxE8zhXYCUA9KwdXaiv5ZV8bh-dNZfdTpGpZA5gBhNHAMWBgIwAno4eJ+GZzWAIGFgFgWHB1HAAcgAavkcABmAkAbiBrxB7ERNJOcDBFgOTBi0K0RCwBjgiN6hwAZq4ALR+KR6THDaBySDkPgTBjmBhi2AsQXUz4C1gsHQEfwilxjAiYvoAVgtmvWOGOFE4WF0BqNKkxAgIsHcVtQQN6tgAjJMfb0cML0JiAEwABkjAFIbaGwGKwBKvcHkURjZjDjqIHqnRmVKnFkCgxdYNdA1rgwnMX7o3GhaLxeQ9EXes6TTbYfEHfrDQWCEWvDSXkzYG0UiAxwxbB7IaIJFO0uxhAhxHEYoRGHDPLQdURyIw7gRV+uogY-PcAMpwyAWVfAHwgXOsFTzhCP2gBViMExPtx+A+IRZOEkTfowy5UIUCQeMkT5yCeECcNwAAs3hAA',
+ }),
+ );
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ // await page.keyboard.insertText(sfc);
+
+ await waitForResultUpdate();
+
+ const headerText = await getResult().innerText('h1');
+
+ // markdown, scss, typescript
+ expect(headerText).toContain(`Hello, Vue 3!`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(85, 85, 85)');
+
+ // css modules
+ expect(await getResult().$eval('p', (e) => getComputedStyle(e).color)).toBe('rgb(0, 128, 0)');
+ });
+
+ test('Vue + Tailwind CSS', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="vue"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
Tailwind in Vue SFC
+
+
+`,
+ );
+
+ await app.click(':nth-match([title="Change Language"], 2)');
+ await app.click('text=Tailwind CSS');
+ await app.click('text=CSS');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `@tailwind base;
+@tailwind components;
+@tailwind utilities;
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Tailwind in Vue SFC`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe(
+ 'rgb(220, 38, 38)',
+ );
+ });
+
+ test('Vue 2', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Vue 2');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+Hello, {{ title }}
+
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Vue 2`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Svelte', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await (await app.$('[data-lang="svelte"]'))?.click();
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
+
Hello, {title}
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Svelte`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Malina.js', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Malina.js');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `
+
+
+
Hello, {title}
+
+`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Malina.js`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('Stencil', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(' ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Stencil');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `import { Component, Prop, h } from "@stencil/core";
+@Component({
+ tag: "my-app",
+ styles: "h1 { color: blue; }",
+})
+export class App {
+ @Prop() title: string;
+ render() {
+ return (
+ Hello, {this.title}
+ );
+ }
+}`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('h1');
+
+ expect(resultText).toContain(`Hello, Stencil`);
+ expect(await getResult().$eval('h1', (e) => getComputedStyle(e).color)).toBe('rgb(0, 0, 255)');
+ });
+
+ test('CoffeeScript', async ({ page, getTestUrl }) => {
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=CoffeeScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`square = (x) -> x * x`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerHTML('body > script');
+
+ expect(resultText).toContain(`var square;`);
+ expect(resultText).toContain(`square = function(x) {
+ return x * x;
+};`);
+ });
+
+ test('LiveScript', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, World ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=LiveScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`{ capitalize, join, map, words } = require 'prelude-ls'
+title = 'live script'
+|> words
+|> map capitalize
+|> join ''
+(document.getElementById \\title).textContent = title`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, LiveScript`);
+ });
+
+ test('Riot.js', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(' ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Riot.js');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, {props.title} ');
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Riot.js`);
+ });
+
+ test('AssemblyScript', async ({ page, getTestUrl }) => {
+ test.fixme();
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(
+ `Hello, World
+ `,
+ );
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=AssemblyScript');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`export function getTitle(): string {return "AssemblyScript";`);
+ // workaround for monaco auto-complete
+ await page.keyboard.press('Delete');
+ await page.keyboard.insertText(`}`);
+
+ await app.waitForTimeout(15000);
+ const resultText = await getResult().innerText('text=Hello, AssemblyScript');
+
+ expect(resultText).toContain(`Hello, AssemblyScript`);
+ });
+
+ test('Python', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Python');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`from browser import document
+title = 'Python'
+document['header'].html = f"Hello, {title}"`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Python`);
+ });
+
+ test('Pyodide', async ({ page, getTestUrl }) => {
+ test.skip();
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Pyodide');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText(`from js import document
+title = 'Python'
+document.getElementById('header').innerHTML = f"Hello, {title}"`);
+
+ await waitForResultUpdate();
+ await getResult().waitForSelector('text=Hello, Python');
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Python`);
+ });
+
+ test('Ruby', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Ruby');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`require "native"
+title = 'Ruby'
+$$.document.querySelector('#title').innerHTML = title`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('text=Hello, Ruby');
+
+ expect(resultText).toContain(`Hello, Ruby`);
+ });
+
+ test('Go', async ({ page, getTestUrl, editor }) => {
+ test.slow();
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Go');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`package main
+import "syscall/js"
+func main() {
+ js.Global().Get("document").Call("querySelector", "#title").Set("innerHTML", "Golang")
+}`);
+
+ await waitForResultUpdate({ delay: 4000, timeout: 60_000 });
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Golang`);
+ });
+
+ test('PHP', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=PHP');
+ await waitForEditorFocus(app);
+
+ // go below pre-inserted 'getElementById('title')->textContent = $title;`,
+ );
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, PHP`);
+ });
+
+ test('Perl', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Perl');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`use strict;
+my $title = 'Perl';
+JS::inline('document.getElementById("title").innerHTML') = $title;`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Perl`);
+ });
+
+ test('Lua', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Lua');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`js = require "js"
+window = js.global
+document = window.document
+document:getElementById("title").innerHTML = "Lua"`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Lua`);
+ });
+
+ test('Scheme', async ({ page, getTestUrl, editor }) => {
+ test.skip(editor === 'codejar', 'please fix');
+
+ await page.goto(getTestUrl());
+
+ const { app, getResult, waitForResultUpdate } = await getLoadedApp(page);
+
+ await app.click('text="HTML"');
+ await waitForEditorFocus(app);
+ await page.keyboard.insertText('Hello, world ');
+
+ await app.click(':nth-match([title="Change Language"], 3)');
+ await app.click('text=Scheme');
+ await waitForEditorFocus(app);
+
+ await page.keyboard.insertText(`(let ((title "Scheme"))
+ (set-content! "#title" title))`);
+
+ await waitForResultUpdate();
+ const resultText = await getResult().innerText('h1');
+
+ expect(resultText).toContain(`Hello, Scheme`);
+ });
+});
diff --git a/functions/vendors/templates.js b/functions/vendors/templates.js
index 10dbce55f7..2bbc7ed68f 100644
--- a/functions/vendors/templates.js
+++ b/functions/vendors/templates.js
@@ -447,10 +447,10 @@ body {
font-size: 3.5rem;
}
}
-`.trimStart()},script:{language:"javascript",content:""},stylesheets:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/css/bootstrap.min.css"],scripts:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"],cssPreset:"",imports:{},types:{}};var y={name:"coffeescript",title:getTemplateName("templates.starter.coffeescript","CoffeeScript Starter"),thumbnail:"assets/templates/coffeescript.svg",activeEditor:"script",markup:{language:"html",content:`
+`.trimStart()},script:{language:"javascript",content:""},stylesheets:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/css/bootstrap.min.css"],scripts:["{{ __CDN_URL__ }}bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"],cssPreset:"",imports:{},types:{}};var y={name:"civet",title:getTemplateName("templates.starter.civet","Civet Starter"),thumbnail:"assets/templates/civet.png",activeEditor:"script",markup:{language:"html",content:`
Hello, World !
-
+
You clicked 0 times.
Click me
@@ -463,25 +463,25 @@ body {
.logo {
width: 150px;
}
-`.trimStart()},script:{language:"coffeescript",content:`
-titleElement = document.getElementById 'title'
-counterElement = document.getElementById 'counter'
-button = document.getElementById 'counter-button'
+`.trimStart()},script:{language:"civet",content:`
+titleElement := document.getElementById 'title'
+counterElement := document.getElementById 'counter'
+button := document.getElementById 'counter-button'
-title = 'CoffeeScript'
+title := 'Civet'
titleElement.innerText = title
-counter = (count) -> -> count += 1
-increment = counter 0
+counter := (count: number) => => count += 1
+increment := counter 0
+function handleClick: void counterElement.innerText = increment()
-button.addEventListener('click',
- -> counterElement.innerText = increment())
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var x={name:"go",title:getTemplateName("templates.starter.go","Go Starter"),thumbnail:"assets/templates/go.svg",activeEditor:"script",markup:{language:"html",content:`
+button.addEventListener 'click', handleClick
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var x={name:"clio",title:getTemplateName("templates.starter.clio","Clio Starter"),thumbnail:"assets/templates/clio.png",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
+
Hello, World!
+
You clicked 0 times.
-
Click me
+
Loading...
`.trimStart()},style:{language:"css",content:`
.container,
@@ -490,62 +490,38 @@ button.addEventListener('click',
font: 1em sans-serif;
}
.logo {
- width: 250px;
+ width: 150px;
}
-`.trimStart()},script:{language:"go",content:`
-package main
-
-import (
- "fmt"
- "syscall/js"
- "time"
-)
-
-func main() {
- title := querySelector("#title")
- title.Set("innerHTML", "Golang")
+`.trimStart()},script:{language:"clio",content:`
+fn capitalize str:
+ (str.charAt 0 -> .toUpperCase) + (str.slice 1 -> .toLowerCase)
- registerCounter()
+fn greet name:
+ f"Hello, {name}!"
- // yes, you can use goroutines (check the console)
- go greet()
- fmt.Println("Hello!")
-}
+fn setTitle name:
+ title = document.querySelector "#title"
+ title.innerText = name -> capitalize -> greet
-func querySelector(id string) js.Value {
- return js.Global().Get("document").Call("querySelector", id)
-}
+fn increment value:
+ (Number value) + 1
-func registerCounter() {
- btn := querySelector("#counter-button")
- counter := querySelector("#counter")
- count := 0
+fn activateBtn btn:
+ btn.disabled = false
+ btn.innerText = "Click me"
+ btn
- var cb js.Func
- cb = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
- count += 1
- counter.Set("innerHTML", count)
- return nil
- })
- btn.Call("addEventListener", "click", cb)
-}
+fn onBtnClick:
+ counter = document.querySelector "#counter"
+ counter.innerText = increment counter.innerText
-func greet() {
- if hours, _, _ := time.Now().Clock(); hours < 12 {
- fmt.Println("Good morning")
- } else if hours < 18 {
- fmt.Println("Good afternoon")
- } else {
- fmt.Println("Good evening")
- }
-}
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var w={name:"jquery",title:getTemplateName("templates.starter.jquery","jQuery Starter"),thumbnail:"assets/templates/jquery.svg",activeEditor:"script",markup:{language:"html",content:`
-
-
Hello, World !
-
-
You clicked 0 times.
-
Click me
-
+export fn main argv:
+ setTitle "clio"
+ document.querySelector "#counter-button"
+ -> activateBtn
+ -> .addEventListener "click" onBtnClick
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var w={name:"clojurescript",title:getTemplateName("templates.starter.clojurescript","ClojureScript Starter"),thumbnail:"assets/templates/cljs.svg",activeEditor:"script",markup:{language:"html",content:`
+Loading...
`.trimStart()},style:{language:"css",content:`
.container,
.container button {
@@ -553,24 +529,43 @@ func greet() {
font: 1em sans-serif;
}
.logo {
- width: 300px;
+ width: 150px;
}
-`.trimStart()},script:{language:"javascript",content:`
-import $ from "jquery";
+`.trimStart()},script:{language:"clojurescript",content:`
+(ns react.component
+ (:require
+ ;; you may use npm packages
+ ["canvas-confetti$default" :as confetti]
+ ["react$default" :as React]
+ ["react" :refer [useState]]
+ ["react-dom/client" :refer [createRoot]]))
-$("#title").text('jQuery');
+(defn Counter [^:js {:keys [name]}]
+ (let [[counter setCount] (useState 0)]
+ #jsx [:div
+ {:className "container"}
+ [:h1 (str "Hello, " name "!")]
+ [:img
+ {:className "logo"
+ :alt "logo"
+ :src "{{ __livecodes_baseUrl__ }}assets/templates/cljs.svg"}]
+ [:p "You clicked " counter " times."]
+ [:button
+ {:onClick (fn []
+ (if (= (mod counter 3) 0) (confetti))
+ (setCount (inc counter)))}
+ "Click me"]]))
-let count = 0;
-$("#counter-button").click(() => {
- count += 1;
- $("#counter").text(count);
-});
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var S={name:"knockout",title:getTemplateName("templates.starter.knockout","Knockout Starter"),thumbnail:"assets/templates/knockout.svg",activeEditor:"script",markup:{language:"html",content:`
+(def title "ClojureScript")
+(print (str "Hello, " title "!"))
+(defonce root (createRoot (js/document.querySelector "#app")))
+(.render root #jsx [Counter #js {:name title}])
+`.trimStart()}};var S={name:"coffeescript",title:getTemplateName("templates.starter.coffeescript","CoffeeScript Starter"),thumbnail:"assets/templates/coffeescript.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
-
You clicked 0 times.
-
Click me
+
Hello, World !
+
+
You clicked 0 times.
+
Click me
`.trimStart()},style:{language:"css",content:`
.container,
@@ -579,27 +574,25 @@ $("#counter-button").click(() => {
font: 1em sans-serif;
}
.logo {
- width: 250px;
+ width: 150px;
}
-`.trimStart()},script:{language:"javascript",content:`
-import ko from "knockout";
+`.trimStart()},script:{language:"coffeescript",content:`
+titleElement = document.getElementById 'title'
+counterElement = document.getElementById 'counter'
+button = document.getElementById 'counter-button'
-class ClickCounterViewModel {
- constructor() {
- this.title = 'Knockout';
- this.numberOfClicks = ko.observable(0);
+title = 'CoffeeScript'
+titleElement.innerText = title
- this.registerClick = function () {
- this.numberOfClicks(this.numberOfClicks() + 1);
- };
- }
-}
+counter = (count) -> -> count += 1
+increment = counter 0
-ko.applyBindings(new ClickCounterViewModel());
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var k={name:"livescript",title:getTemplateName("templates.starter.livescript","LiveScript Starter"),thumbnail:"assets/templates/livescript.svg",activeEditor:"script",markup:{language:"html",content:`
+button.addEventListener('click',
+ -> counterElement.innerText = increment())
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var k={name:"commonlisp",title:getTemplateName("templates.starter.commonlisp","Common Lisp Starter"),thumbnail:"assets/templates/commonlisp.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
+
Hello, World!
+
You clicked 0 times.
Click me
@@ -612,31 +605,70 @@ ko.applyBindings(new ClickCounterViewModel());
.logo {
width: 150px;
}
-`.trimStart()},script:{language:"livescript",content:`
-{ capitalize, join, map, words } = require 'prelude-ls'
-
-title = 'live script'
-|> words
-|> map capitalize
-|> join ''
-
-(document.getElementById \\title).innerText = title
+`.trimStart()},script:{language:"commonlisp",content:`
+(defun set-attribute (&key selector attribute value)
+ (let ((node
+ (#j:document:querySelector selector)))
+ (setf (jscl::oget node attribute) value)
+ node))
-increment = (count) -> -> count += 1
-counter = increment 0
+(let ((title "Common Lisp"))
+ (set-attribute :selector "#title" :attribute "innerHTML"
+ :value (format nil "Hello, ~A!" title)))
-counter-element = document.getElementById \\counter
-button = document.getElementById \\counter-button
+(let ((counter 0))
+ (set-attribute :selector "#counter-button" :attribute "onclick"
+ :value #'(lambda (ev)
+ (setf counter (+ counter 1))
+ (set-attribute :selector "#counter" :attribute "innerHTML"
+ :value counter))))
-button.addEventListener \\click,
- -> counter-element.innerText = counter!
-`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var _={name:"lua",title:getTemplateName("templates.starter.lua","Lua Starter"),thumbnail:"assets/templates/lua.svg",activeEditor:"script",markup:{language:"html",content:`
+(#j:console:clear)
+(write "Hello, Common Lisp!")
+`.trimStart()},stylesheets:[],scripts:[],cssPreset:"",imports:{},types:{}};var _={name:"cpp",title:getTemplateName("templates.starter.cpp","C++ Starter"),thumbnail:"assets/templates/cpp.svg",activeEditor:"script",markup:{language:"html",content:`
-
Hello, World !
-
-
You clicked 0 times.
+
Hello, World !
+
+
You clicked 0 times.
Click me
+
+
+`.trimStart(),
+ },
+ style: {
+ language: 'css',
+ content: `
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 20px;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+}
+
+.logo {
+ width: 150px;
+ display: block;
+ margin: 20px auto;
+}
+
+.demo-section {
+ background: #f5f5f5;
+ padding: 20px;
+ margin: 20px 0;
+ border-radius: 8px;
+ border-left: 4px solid #00add8;
+}
+
+.demo-section h2 {
+ margin-top: 0;
+ color: #333;
+}
+
+button {
+ background: #00add8;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 16px;
+ margin: 10px 5px;
+}
+
+button:hover:not(:disabled) {
+ background: #0099c7;
+}
+
+button:disabled {
+ background: #ccc;
+ cursor: not-allowed;
+}
+
+input[type="text"], input[type="number"] {
+ padding: 8px 12px;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ font-size: 16px;
+ margin: 5px;
+ width: 200px;
+}
+
+#counter {
+ font-weight: bold;
+ color: #00add8;
+ font-size: 24px;
+}
+
+#greeting, #result {
+ font-weight: bold;
+ color: #333;
+ margin-top: 10px;
+}
+`.trimStart(),
+ },
+ script: {
+ language: 'go-wasm',
+ content: `
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+func main() {
+ // Read input from stdin
+ scanner := bufio.NewScanner(os.Stdin)
+
+ if scanner.Scan() {
+ input := strings.TrimSpace(scanner.Text())
+
+ if count, err := strconv.Atoi(input); err == nil {
+ newCount := count + 1
+ fmt.Println(newCount)
+ return
+ }
+
+ fmt.Printf("Hello, %s!\\n", input)
+ } else {
+ fmt.Println("Hello from Go WebAssembly!")
+ }
+}
+`.trimStart(),
+ },
+};
diff --git a/src/livecodes/templates/starter/index.ts b/src/livecodes/templates/starter/index.ts
index 1075d26834..9f8a22eb10 100644
--- a/src/livecodes/templates/starter/index.ts
+++ b/src/livecodes/templates/starter/index.ts
@@ -21,6 +21,7 @@ import { diagramsStarter } from './diagrams-starter';
import { fennelStarter } from './fennel-starter';
import { gleamStarter } from './gleam-starter';
import { goStarter } from './go-starter';
+import { goWasmStarter } from './go-wasm-starter';
import { imbaStarter } from './imba-starter';
import { javaStarter } from './java-starter';
import { javascriptStarter } from './javascript-starter';
@@ -111,6 +112,7 @@ export const starterTemplates = [
rubyStarter,
rubyWasmStarter,
goStarter,
+ goWasmStarter,
phpStarter,
phpWasmStarter,
cppStarter,
diff --git a/src/livecodes/vendors.ts b/src/livecodes/vendors.ts
index 3ee6afdcfc..2207984b32 100644
--- a/src/livecodes/vendors.ts
+++ b/src/livecodes/vendors.ts
@@ -99,6 +99,8 @@ export const cppWasmBaseUrl = /* @__PURE__ */ getUrl('@chriskoch/cpp-wasm@1.0.2/
export const csharpWasmBaseUrl = /* @__PURE__ */ getUrl('@seth0x41/csharp-wasm@1.0.3/');
+export const yaegiWasmBaseUrl = /* @__PURE__ */ getUrl('yaegi-wasm@1.0.2/src/');
+
export const csstreeUrl = /* @__PURE__ */ getUrl('css-tree@2.3.1/dist/csstree.js');
export const cytoscapeSvgUrl = /* @__PURE__ */ getUrl('cytoscape-svg@0.4.0/cytoscape-svg.js');
diff --git a/src/sdk/models.ts b/src/sdk/models.ts
index 50695a9bdd..adebd1a1ae 100644
--- a/src/sdk/models.ts
+++ b/src/sdk/models.ts
@@ -968,6 +968,8 @@ export type Language =
| 'riotjs'
| 'malina'
| 'malinajs'
+ | 'ripple'
+ | 'ripplejs'
| 'xht'
| 'coffeescript'
| 'coffee'
@@ -998,6 +1000,9 @@ export type Language =
| 'rubywasm'
| 'go'
| 'golang'
+ | 'go-wasm'
+ | 'wasm.go'
+ | 'gowasm'
| 'php'
| 'php-wasm'
| 'phpwasm'
@@ -1350,6 +1355,7 @@ export interface Compiler {
| 'text/commonlisp'
| 'text/tcl'
| 'text/prolog'
+ | 'text/go-wasm'
| 'application/json'
| 'application/lua'
| 'text/fennel'
@@ -1418,6 +1424,7 @@ export type TemplateName =
| 'ruby'
| 'ruby-wasm'
| 'go'
+ | 'go-wasm'
| 'php'
| 'php-wasm'
| 'cpp'
diff --git a/vendor-licenses.md b/vendor-licenses.md
index c3049f5b7c..a22b29a64e 100644
--- a/vendor-licenses.md
+++ b/vendor-licenses.md
@@ -315,3 +315,7 @@ WebR: [License](https://github.com/r-wasm/webr/blob/e47ab9854c9306c410f302579c66
Whirl: [MIT License](https://github.com/jh3y/whirl/tree/8de79b76a13200ccbd8b0b75b4f79978ef1ee890)
Windi CSS: [MIT License](https://github.com/windicss/windicss/blob/bcd50d877e62630f191602ddeabd9f677cc6d90c/LICENSE)
+
+Yaegi: [Apache License 2.0](https://github.com/traefik/yaegi/blob/d93266d013f393a20122ef0dd3f579d411a066be/LICENSE)
+
+yaegi-wasm: [Apache License 2.0](https://github.com/Muhammad-Ayman/yaegi-wasm/blob/528a6bbac7464dc8911e50e0d617512f3e247e8c/LICENSE)