Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix launching extension in safari #10908

Merged
merged 10 commits into from
Jul 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@
"problemMatcher": [],
"label": "preTestJediLSP"
},
{
"type": "npm",
"script": "launchWebExtension",
"problemMatcher": [],
"label": "Launch Web Extension (Chrome)"
},
{
"type": "shell",
"problemMatcher": [],
"command": "npm",
"args": ["run", "launchWebExtension", "--", "--browser=webkit", "--port=3111"],
"label": "Launch Web Extension (Safari)"
},
{
"type": "npm",
"script": "lint",
Expand All @@ -88,7 +101,7 @@
"options": {
"env": {
"CI_PYTHON_PATH": "", // Update with path to real python interpereter used for testing.
"EXISTING_JUPYTER_URI": "", // Update with a server that you started yourself to avoid this script doing it
"EXISTING_JUPYTER_URI": "" // Update with a server that you started yourself to avoid this script doing it
}
}
},
Expand Down
23 changes: 22 additions & 1 deletion build/ci/postInstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const colors = require('colors/safe');
const fs = require('fs-extra');
const path = require('path');
const constants = require('../constants');
const child_process = require('child_process');

/**
* In order to get raw kernels working, we reuse the default kernel that jupyterlab ships.
Expand Down Expand Up @@ -125,7 +124,29 @@ function fixJupyterLabRenderers() {
}
}

/**
* Ensures extension loads in safari (https://github.com/microsoft/vscode-jupyter/issues/10621)
* Some of the regexes are not supported in safari and not required either.
*/
function fixStripComments() {
const file = 'node_modules/strip-comments/lib/languages.js';
const filePath = path.join(__dirname, '..', '..', file);
if (!fs.existsSync(filePath)) {
return;
}
const contents = `
'use strict';

exports.javascript = {
BLOCK_OPEN_REGEX: /^\\/\\*\\*?(!?)/,
BLOCK_CLOSE_REGEX: /^\\*\\/(\\n?)/,
LINE_REGEX: /^\\/\\/(!?).*/
};`;
fs.writeFileSync(filePath, contents);
}

fixJupyterLabRenderers();
makeVariableExplorerAlwaysSorted();
createJupyterKernelWithoutSerialization();
updateJSDomTypeDefinition();
fixStripComments();
6 changes: 6 additions & 0 deletions build/launchWeb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { launch } = require('./launchWebUtils');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added ability to launch extension in vscode web locally


void launch();
58 changes: 2 additions & 56 deletions build/launchWebTest.js
Original file line number Diff line number Diff line change
@@ -1,60 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const path = require('path');
const fs = require('fs-extra');
const test_web = require('@vscode/test-web');
const { startJupyter } = require('./preLaunchWebTest');
const jsonc = require('jsonc-parser');
const { startReportServer } = require('./webTestReporter');
const { noop } = require('../out/test/core');
const { isCI } = require('./constants');
const extensionDevelopmentPath = path.resolve(__dirname, '../');
const packageJsonFile = path.join(extensionDevelopmentPath, 'package.json');
const { launch } = require('./launchWebUtils');

async function go() {
let exitCode = 0;
let server;
let testServer;
try {
server = (await startJupyter()).server;
testServer = await startReportServer();
const bundlePath = path.join(extensionDevelopmentPath, 'out', 'extension.web.bundle');

// Changing the logging level to be read from workspace settings file.
// This way we can enable verbose logging and get the logs for web tests.
const settingsJson = fs.readFileSync(packageJsonFile).toString();
const edits = jsonc.modify(
settingsJson,
['contributes', 'configuration', 'properties', 'jupyter.logging.level', 'scope'],
'resource',
{}
);
const updatedSettingsJson = jsonc.applyEdits(settingsJson, edits);
fs.writeFileSync(packageJsonFile, updatedSettingsJson);

// Now run the test
await test_web.runTests({
browserType: 'chromium',
verbose: true,
headless: isCI ? false : true, // Set this to false to debug failures (false on CI to support capturing screenshots when tests fail).
extensionDevelopmentPath,
folderPath: path.resolve(__dirname, '..', 'src', 'test', 'datascience'),
extensionTestsPath: bundlePath
});
} catch (err) {
console.error('Failed to run tests', err);
exitCode = 1;
} finally {
if (testServer) {
await testServer.dispose().catch(noop);
}
if (server) {
await server.dispose();
}
}

// Not all promises complete. Force exit
process.exit(exitCode);
}
void go();
void launch(true);
69 changes: 69 additions & 0 deletions build/launchWebUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const path = require('path');
const fs = require('fs-extra');
const test_web = require('@vscode/test-web');
const { startJupyter } = require('./preLaunchWebTest');
const jsonc = require('jsonc-parser');
const { startReportServer } = require('./webTestReporter');
const { noop } = require('../out/test/core');
const { isCI } = require('./constants');
const extensionDevelopmentPath = path.resolve(__dirname, '../');
const packageJsonFile = path.join(extensionDevelopmentPath, 'package.json');
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv)).argv;

const browserType = argv.browser || argv.browserType || 'chromium';
const port = argv.port || 3000;

exports.launch = async function launch(launchTests) {
let exitCode = 0;
let server;
let testServer;
try {
if (launchTests) {
server = (await startJupyter()).server;
testServer = await startReportServer();
}
const bundlePath = path.join(extensionDevelopmentPath, 'out', 'extension.web.bundle');

// Changing the logging level to be read from workspace settings file.
// This way we can enable verbose logging and get the logs for web tests.
const settingsJson = fs.readFileSync(packageJsonFile).toString();
const edits = jsonc.modify(
settingsJson,
['contributes', 'configuration', 'properties', 'jupyter.logging.level', 'scope'],
'resource',
{}
);
const updatedSettingsJson = jsonc.applyEdits(settingsJson, edits);
fs.writeFileSync(packageJsonFile, updatedSettingsJson);
const options = {
browserType,
verbose: true,
port,
headless: isCI ? false : false, // Set this to false to debug failures (false on CI to support capturing screenshots when tests fail).
extensionDevelopmentPath,
folderPath: path.resolve(__dirname, '..', 'src', 'test', 'datascience')
};
if (launchTests) {
options.extensionTestsPath = bundlePath;
}
await test_web.runTests(options);
} catch (err) {
console.error(launchTests ? 'Failed to run tests' : 'Failed to launch VS Code', err);
exitCode = 1;
} finally {
if (testServer) {
await testServer.dispose().catch(noop);
}
if (server) {
await server.dispose();
}
}

// Not all promises complete. Force exit
process.exit(exitCode);
};
1 change: 1 addition & 0 deletions news/2 Fixes/10621.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ensure the extension loads in the `Safari` browser.
7 changes: 3 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2195,6 +2195,7 @@
"testNativeNotebooksWithoutPythonInVSCode": "cross-env CODE_TESTS_WORKSPACE=src/test/datascience VSC_JUPYTER_CI_TEST_VSC_CHANNEL=insiders TEST_FILES_SUFFIX=*.vscode.test,*.vscode.common.test VSC_JUPYTER_FORCE_LOGGING=1 VSC_JUPYTER_LOAD_EXPERIMENTS_FROM_FILE=true VSC_JUPYTER_CI_TEST_GREP=non-python-kernel VSC_JUPYTER_CI_TEST_DO_NOT_INSTALL_PYTHON_EXT=true node ./out/test/testBootstrap.node.js ./out/test/standardTest.node.js",
"testNativeNotebooksAndWebviews": "cross-env CODE_TESTS_WORKSPACE=src/test/datascience VSC_JUPYTER_CI_TEST_VSC_CHANNEL=insiders TEST_FILES_SUFFIX=*.vscode.test,*.vscode.common.test VSC_JUPYTER_FORCE_LOGGING=1 VSC_JUPYTER_CI_TEST_GREP=webview-test VSC_JUPYTER_LOAD_EXPERIMENTS_FROM_FILE=true node ./out/test/testBootstrap.node.js ./out/test/standardTest.node.js",
"testWebExtension": "node ./build/launchWebTest.js",
"launchWebExtension": "node ./build/launchWeb.js",
"testPerformance": "node ./out/test/perfTest.node.js",
"testSmoke": "node ./out/test/testBootstrap.node.js ./out/test/smokeTest.node.js",
"testSmokeLogged": "cross-env VSC_JUPYTER_FORCE_LOGGING=true VSC_JUPYTER_LOG_FILE=smoke-test.log node --no-force-async-hooks-checks ./out/test/testBootstrap.node.js ./out/test/smokeTest.node.js",
Expand Down Expand Up @@ -2273,6 +2274,7 @@
"safe-buffer": "^5.2.1",
"sanitize-filename": "^1.6.3",
"semver": "^5.5.0",
"setimmediate": "^1.0.5",
"slickgrid": "^2.4.17",
"source-map": "^0.7.3",
"stack-trace": "0.0.10",
Expand Down
7 changes: 7 additions & 0 deletions src/extension.web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ if ((Reflect as any).metadata === undefined) {
require('reflect-metadata');
}

// Polly fill for webworkers in safari,
// The scripts load in chrome because chrome supports offScreenCanvas which in turn supports requestAnimationFrame,
// & requestAnimationFrame is the preferred approach and setImmediate is the fallback.
// As requestAnimationFrame is supported in chrome webworkers there's no need for a fallback to setImmediate.
// https://github.com/microsoft/vscode-jupyter/issues/10621
require('setimmediate');

// Initialize the logger first.
require('./platform/logging');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export function extractRequireConfigFromWidgetEntry(baseUrl: Uri, widgetFolderNa
// the config entry is js, and not json.
// We cannot eval as thats dangerous, and we cannot use JSON.parse either as it not JSON.
// Lets just extract what we need.
configStr = stripComments(configStr);
configStr = stripComments(configStr, { language: 'javascript' });
configStr = configStr.splitLines({ trim: true, removeEmptyEntries: true }).join('');
// Now that we have just valid JS, extract contents between the third '{' and corresponding ending '}'
const mappings = configStr
Expand Down