Skip to content

Commit cfb7e5c

Browse files
authored
Merge pull request #197 from JetBrains/fix-browser-platforms
Add JS and Wasm for 2.0.x version
2 parents f1bc675 + 54a2ecb commit cfb7e5c

File tree

13 files changed

+197
-40
lines changed

13 files changed

+197
-40
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"@babel/plugin-transform-runtime": "~7.22.4",
2121
"@babel/preset-env": "~7.22.4",
2222
"@babel/runtime-corejs2": "~7.22.2",
23-
"@playwright/test": "^1.37.1",
23+
"@playwright/test": "^1.40.1",
2424
"@typescript-eslint/eslint-plugin": "^6.4.0",
2525
"@typescript-eslint/parser": "^6.4.0",
2626
"babel-loader": "^9.1.3",

src/executable-code/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export default class ExecutableCode {
8686
const args = targetNode.hasAttribute(ATTRIBUTES.ARGUMENTS) ? targetNode.getAttribute(ATTRIBUTES.ARGUMENTS) : "";
8787
const hiddenDependencies = this.getHiddenDependencies(targetNode);
8888
const outputHeight = targetNode.getAttribute(ATTRIBUTES.OUTPUT_HEIGHT) || null;
89-
const targetPlatform = getTargetById(targetNode.getAttribute(ATTRIBUTES.PLATFORM));
89+
const targetPlatform = getTargetById(targetNode.getAttribute(ATTRIBUTES.PLATFORM)) || TargetPlatforms.JAVA;
9090
const targetNodeStyle = targetNode.getAttribute(ATTRIBUTES.STYLE);
9191
const jsLibs = this.getJsLibraries(targetNode, targetPlatform);
9292
const isFoldedButton = targetNode.getAttribute(ATTRIBUTES.FOLDED_BUTTON) !== "false";

src/lib/crosslink.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { compressToBase64 } from 'lz-string';
22

3-
import { isKeyOfObject } from '../utils/types';
4-
import { TargetPlatforms, TargetPlatformsKeys } from '../utils/platforms';
3+
import { getTargetById, TargetPlatformsKeys } from '../utils/platforms';
54

65
import {
76
escapeRegExp,
@@ -34,11 +33,8 @@ export function generateCrosslink(code: string, options?: LinkOptions) {
3433

3534
if (options && options.targetPlatform) {
3635
const target =
37-
options.targetPlatform && options.targetPlatform.toUpperCase();
38-
39-
if (!isKeyOfObject(target, TargetPlatforms))
40-
throw new Error('Invalid target platform');
41-
36+
options.targetPlatform && getTargetById(options.targetPlatform);
37+
if (!target) throw new Error('Invalid target platform');
4238
opts.targetPlatform = options.targetPlatform;
4339
}
4440

src/utils/platforms/TargetPlatform.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export default class TargetPlatform {
2-
private id: string;
3-
private printableName: string;
2+
id: string;
3+
printableName: string;
44

55
constructor(id: string, printableName: string) {
66
this.id = id;

src/utils/platforms/index.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
import { isKeyOfObject } from '../types';
2-
31
import TargetPlatform from './TargetPlatform';
42
import { TargetPlatforms } from './TargetPlatforms';
3+
import { isKeyOfObject } from '../types';
54

65
export function getTargetById(id?: string | null) {
7-
const key = id && id.toUpperCase();
8-
return key && isKeyOfObject(key, TargetPlatforms)
9-
? TargetPlatforms[key]
10-
: TargetPlatforms.JAVA;
6+
const key = id && id.toUpperCase().replace(/-/g, '_');
7+
8+
return isKeyOfObject(key, TargetPlatforms) ? TargetPlatforms[key] : null;
119
}
1210

1311
export function isJavaRelated(platform: TargetPlatform) {

src/webdemo-api.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,27 +50,26 @@ export default class WebDemoApi {
5050
* @returns {*|PromiseLike<T>|Promise<T>}
5151
*/
5252
static translateKotlinToJs(code, compilerVersion, platform, args, hiddenDependencies) {
53-
const MINIMAL_MINOR_VERSION_IR = 5
54-
const MINIMAL_MINOR_VERSION_WASM = 9
55-
const minor = parseInt(compilerVersion.split(".")[1]);
53+
const MINIMAL_VERSION_IR = '1.5.0';
54+
const MINIMAL_VERSION_WASM = '1.9.0';
5655

57-
if (platform === TargetPlatforms.JS_IR && minor < MINIMAL_MINOR_VERSION_IR) {
56+
if (platform === TargetPlatforms.JS_IR && compilerVersion < MINIMAL_VERSION_IR) {
5857
return Promise.resolve({
5958
output: "",
6059
errors: [{
6160
severity: "ERROR",
62-
message: `JS IR compiler backend accessible only since 1.${MINIMAL_MINOR_VERSION_IR}.0 version`
61+
message: `JS IR compiler backend accessible only since ${MINIMAL_VERSION_IR} version`
6362
}],
6463
jsCode: ""
6564
})
6665
}
6766

68-
if (platform === TargetPlatforms.WASM && minor < MINIMAL_MINOR_VERSION_WASM) {
67+
if (platform === TargetPlatforms.WASM && compilerVersion < MINIMAL_VERSION_WASM) {
6968
return Promise.resolve({
7069
output: "",
7170
errors: [{
7271
severity: "ERROR",
73-
message: `Wasm compiler backend accessible only since 1.${MINIMAL_MINOR_VERSION_WASM}.0 version`
72+
message: `Wasm compiler backend accessible only since ${MINIMAL_VERSION_WASM} version`
7473
}],
7574
jsCode: ""
7675
})

tests/crosslink.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ test.describe('crosslink: library', () => {
1818
checkLink(generateCrosslink('simple'), { code: 'simple' });
1919

2020
// Pass platforms with codeWithSample
21-
checkLink(generateCrosslink('platform', { targetPlatform: 'JAVA' }), {
21+
checkLink(generateCrosslink('platform', { targetPlatform: 'js-ir' }), {
2222
code: 'platform',
23-
targetPlatform: 'JAVA',
23+
targetPlatform: 'js-ir',
2424
});
2525

2626
// Invalid target

tests/restrictions.e2e.ts

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { expect, Page, test } from '@playwright/test';
2+
3+
import { readFileSync } from 'fs';
4+
import { join } from 'path';
5+
6+
import { gotoHtmlWidget } from './utlis/server/playground';
7+
8+
import { RESULT_SELECTOR, WIDGET_SELECTOR } from './utlis/selectors';
9+
10+
import { prepareNetwork, printlnCode } from './utlis';
11+
import { mockRunRequest, waitRunRequest } from './utlis/mocks/compiler';
12+
import { runButton } from './utlis/interactions';
13+
import { makeJSPrintCode } from './utlis/mocks/result';
14+
15+
const OUTPUTS = Object.freeze({
16+
'js-ir': {
17+
jsCode: makeJSPrintCode('Hello, world!'),
18+
errors: { 'File.kt': [] },
19+
exception: null,
20+
text: '<outStream>Hello, world!\n</outStream>',
21+
},
22+
wasm: JSON.parse(
23+
readFileSync(join(__dirname, 'utlis/mocks/wasm.json'), 'utf-8'),
24+
),
25+
});
26+
27+
const VERSIONS = [
28+
{ version: '1.3.10' },
29+
{ version: '1.9.20', latestStable: true },
30+
{ version: '2.0.1' },
31+
] as const;
32+
33+
test.describe('platform restrictions', () => {
34+
test.beforeEach(async ({ page, baseURL }) => {
35+
await prepareNetwork(page, baseURL, {
36+
versions: (route) =>
37+
route.fulfill({
38+
body: JSON.stringify(VERSIONS),
39+
}),
40+
}); // offline mode
41+
});
42+
43+
test('JS_IR for unsupported version', async ({ page }) => {
44+
await shouldFailedRun(
45+
page,
46+
'js-ir',
47+
'1.3.10',
48+
'JS IR compiler backend accessible only since 1.5.0 version',
49+
);
50+
});
51+
52+
test('JS_IR for supported by minor version', async ({ page }) => {
53+
await shouldSuccessRun(page, 'js-ir', '1.9.0');
54+
});
55+
56+
test('JS_IR for supported by major version', async ({ page }) => {
57+
await shouldSuccessRun(page, 'js-ir', '2.0.1');
58+
});
59+
60+
test('WASM for unsupported version', async ({ page }) => {
61+
await shouldFailedRun(
62+
page,
63+
'wasm',
64+
'1.3.10',
65+
'Wasm compiler backend accessible only since 1.9.0 version',
66+
);
67+
});
68+
69+
test('WASM for supported by minor version', async ({ page, browserName }) => {
70+
test.skip(
71+
browserName !== 'chromium',
72+
"WASM doesn't supported in this browser",
73+
);
74+
await shouldSuccessRun(page, 'wasm', '1.9.0');
75+
});
76+
77+
test('WASM for supported by major version', async ({ page, browserName }) => {
78+
test.skip(
79+
browserName !== 'chromium',
80+
"WASM doesn't supported in this browser",
81+
);
82+
await shouldSuccessRun(page, 'wasm', '2.0.1');
83+
});
84+
});
85+
86+
async function shouldSuccessRun(
87+
page: Page,
88+
platform: keyof typeof OUTPUTS,
89+
version: string,
90+
) {
91+
await gotoHtmlWidget(
92+
page,
93+
{ selector: 'code', version: version },
94+
/* language=html */ `
95+
<code data-target-platform='${platform}'>${printlnCode(
96+
'Hello, world!',
97+
)}</code>
98+
`,
99+
);
100+
101+
const resolveRun = await mockRunRequest(page);
102+
103+
const editor = page.locator(WIDGET_SELECTOR);
104+
105+
await Promise.all([waitRunRequest(page), runButton(editor)]);
106+
107+
resolveRun({
108+
json: Object.freeze(OUTPUTS[platform]),
109+
});
110+
111+
// playground loaded
112+
await expect(editor.locator(RESULT_SELECTOR)).toBeVisible();
113+
await expect(editor.locator(RESULT_SELECTOR)).toContainText('Hello, world!');
114+
}
115+
116+
async function shouldFailedRun(
117+
page: Page,
118+
platform: string,
119+
version: string,
120+
text: string,
121+
) {
122+
await gotoHtmlWidget(
123+
page,
124+
{ selector: 'code', version: version },
125+
/* language=html */ `
126+
<code data-target-platform='${platform}'>${printlnCode(
127+
'Hello, world!',
128+
)}</code>
129+
`,
130+
);
131+
132+
const editor = page.locator(WIDGET_SELECTOR);
133+
await runButton(editor);
134+
135+
await expect(editor.locator(RESULT_SELECTOR)).toBeVisible();
136+
await expect(
137+
editor.locator(RESULT_SELECTOR).locator('.test-fail'),
138+
).toContainText(text);
139+
}

tests/utlis/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ export async function refuseExternalUrls(
1919
export async function prepareNetwork(
2020
page: Page | BrowserContext,
2121
baseURL: string,
22+
options?: {
23+
versions: Parameters<typeof mockVersions>[1];
24+
},
2225
) {
2326
const unRefuse = await refuseExternalUrls(page, baseURL);
24-
const unVersions = await mockVersions(page);
27+
const unVersions = await mockVersions(page, options?.versions);
2528

2629
return async () => {
2730
await unVersions();

tests/utlis/mocks/compiler.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ function isRunRequest(url: URL | string) {
3030

3131
return (
3232
uri.host === API_HOST &&
33-
uri.pathname.match(/^\/?\/api\/\d+\.\d+\.\d+\/compiler\/run$/) !== null
33+
(uri.pathname.match(/^\/?\/api\/\d+\.\d+\.\d+\/compiler\/run$/) !== null ||
34+
uri.pathname.match(/^\/?\/api\/\d+\.\d+\.\d+\/compiler\/translate$/) !==
35+
null)
3436
);
3537
}
3638

0 commit comments

Comments
 (0)