Skip to content
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
8 changes: 7 additions & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,14 @@ jobs:
- name: Install dependencies
run: npm install --ignore-scripts
- name: Build
run: npm run build --ws --if-present
run: npm run build
- name: Install Playwright browsers
if: matrix.os == 'ubuntu-latest'
run: npx playwright install --with-deps
- name: Run tests
run: npm run coverage
- name: Run e2e tests
if: matrix.os == 'ubuntu-latest'
run: npm run test:e2e
- name: Send coverage report to Codecov
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ typings/
.next

nsecure-result.json
!**/fixtures/nsecure-result.json
vuln.json
tmp/
dist/
Expand All @@ -73,3 +74,6 @@ reports
.DS_Store

.claude

# playwright test results
test-results
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"build:workspaces": "npm run build --ws --if-present",
"test": "npm run test:cli && npm run lint && npm run lint:css",
"test:cli": "node --no-warnings --test \"test/**/*.test.js\"",
"test:e2e": "playwright test",
"test:all": "npm run test --ws --if-present",
"coverage": "c8 --reporter=lcov npm run test",
"ci:publish": "changeset publish",
Expand Down Expand Up @@ -79,6 +80,7 @@
"@openally/config.eslint": "^2.4.2",
"@openally/config.typescript": "1.3.0",
"@openally/httpie": "1.1.2",
"@playwright/test": "^1.50.0",
"@stylistic/stylelint-plugin": "5.0.1",
"@types/node": "25.5.0",
"c8": "11.0.0",
Expand Down
15 changes: 15 additions & 0 deletions playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Import Third-party Dependencies
import { defineConfig } from "@playwright/test";

export default defineConfig({
testDir: "./test/e2e",
use: {
baseURL: "http://localhost:3000"
},
webServer: {
command: "node . open ./test/e2e/fixtures/nsecure-result.json --port 3000 --ws-port 1339",
env: { NODESECURE_NO_OPEN: true },
port: 3000,
timeout: 15_000
}
});
4 changes: 3 additions & 1 deletion src/commands/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ export async function start(
const link = `http://localhost:${httpServer.address().port}`;
console.log(kleur.magenta().bold(await i18n.getToken("cli.http_server_started")), kleur.cyan().bold(link));

open(link);
if (Boolean(process.env.NODESECURE_NO_OPEN) === false) {
open(link);
}
});

new WebSocketServerInstanciator({
Expand Down
225 changes: 225 additions & 0 deletions test/e2e/fixtures/nsecure-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
{
"id": "j6vlz7",
"rootDependency": {
"name": "ms",
"version": "2.1.3",
"integrity": "sha512-EY5JVSmS/ZEMr9kLaphuJfQMLLbK87KibiJPcp3GB4YQHlFK6Ynk9mr3WRVyYqKw8akoxIoZfzLWnBTREgvbmw=="
},
"scannerVersion": "10.8.0",
"vulnerabilityStrategy": "none",
"warnings": [],
"highlighted": {
"contacts": [],
"packages": [],
"identifiers": []
},
"dependencies": {
"ms": {
"versions": {
"2.1.3": {
"id": 0,
"type": "cjs",
"usedBy": {},
"isDevDependency": false,
"existOnRemoteRegistry": true,
"flags": [
"hasWarnings"
],
"warnings": [
{
"kind": "unsafe-regex",
"location": [
[
53,
14
],
[
53,
144
]
],
"source": "JS-X-Ray",
"i18n": "sast_warnings.unsafe_regex",
"severity": "Warning",
"experimental": false,
"value": "^(-?(?:\\d+)?\\.?\\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$",
"file": "index.js"
}
],
"dependencyCount": 0,
"gitUrl": null,
"alias": {},
"description": "Tiny millisecond conversion utility",
"size": 6913,
"author": null,
"scripts": {
"precommit": "lint-staged",
"lint": "eslint lib/* bin/*",
"test": "mocha tests.js"
},
"licenses": [
{
"licenses": {
"MIT": "https://spdx.org/licenses/MIT.html#licenseText"
},
"spdx": {
"osi": true,
"fsf": true,
"fsfAndOsi": true,
"includesDeprecated": false
},
"fileName": "package.json"
},
{
"licenses": {
"MIT": "https://spdx.org/licenses/MIT.html#licenseText"
},
"spdx": {
"osi": true,
"fsf": true,
"fsfAndOsi": true,
"includesDeprecated": false
},
"fileName": "license.md"
}
],
"uniqueLicenseIds": [
"MIT"
],
"composition": {
"extensions": [
".md",
".js",
".json"
],
"files": [
"index.js",
"license.md",
"package.json",
"readme.md"
],
"minified": [],
"unused": [],
"missing": [],
"required_files": [],
"required_nodejs": [],
"required_thirdparty": [],
"required_subpath": {}
},
"repository": "vercel/ms",
"integrity": "1f743a8b72bd7a02b88d452246f50ff14164f32e",
"links": {
"npm": "https://www.npmjs.com/package/ms/v/2.1.3",
"homepage": "https://github.com/vercel/ms#readme",
"repository": "https://github.com/vercel/ms"
}
}
},
"vulnerabilities": [],
"metadata": {
"homepage": "https://github.com/vercel/ms#readme",
"publishedCount": 32,
"lastVersion": "2.1.3",
"lastUpdateAt": "2020-12-08T13:54:35.223Z",
"hasReceivedUpdateInOneYear": false,
"hasChangedAuthor": false,
"integrity": {
"2.1.3": "1f743a8b72bd7a02b88d452246f50ff14164f32e"
},
"author": {
"name": "rauchg",
"email": "rauchg@gmail.com"
},
"publishers": [
{
"name": "vercel-release-bot",
"email": "infra+release@vercel.com",
"version": "4.0.0-nightly.202508271359",
"at": "2025-08-27T14:00:01.232Z"
},
{
"name": "leerobinson",
"email": "lrobinson2011@gmail.com",
"version": "3.0.0-canary.1",
"at": "2021-09-15T15:40:43.956Z"
},
{
"name": "mrmckeb",
"email": "mrmckeb.npm@outlook.com",
"version": "3.0.0-beta.2",
"at": "2021-08-25T16:55:32.842Z"
},
{
"name": "styfle",
"email": "steven@ceriously.com",
"version": "2.1.3",
"at": "2020-12-08T13:54:35.223Z"
},
{
"name": "leo",
"email": "leo@zeit.co",
"version": "2.1.1",
"at": "2017-11-30T18:30:16.876Z"
},
{
"name": "rauchg",
"email": "rauchg@gmail.com",
"version": "0.7.1",
"at": "2015-04-20T23:38:57.957Z"
}
],
"maintainers": [
{
"email": "matheus.frndes@gmail.com",
"name": "matheuss"
},
{
"email": "rauchg@gmail.com",
"name": "rauchg"
},
{
"email": "nick.tracey@vercel.com",
"name": "nick.tracey"
},
{
"email": "infra+release@vercel.com",
"name": "vercel-release-bot"
},
{
"email": "team@zeit.co",
"name": "zeit-bot"
},
{
"email": "matt.j.straka@gmail.com",
"name": "matt.straka"
}
],
"hasManyPublishers": false
}
}
},
"metadata": {
"startedAt": 1774800760807,
"executionTime": 1250,
"apiCalls": [
{
"name": "pacote.manifest ms@2.1.3",
"startedAt": 1774800760809,
"executionTime": 7
},
{
"name": "pacote.extract ms@2.1.3",
"startedAt": 1774800760821,
"executionTime": 114
},
{
"name": "tarball.scanDirOrArchive ms@2.1.3",
"startedAt": 1774800760938,
"executionTime": 330
}
],
"apiCallsCount": 3,
"errorCount": 0,
"errors": []
}
}
76 changes: 76 additions & 0 deletions test/e2e/navigation.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Import Third-party Dependencies
import { test, expect } from "@playwright/test";

// CONSTANTS
const kDataMenus = [
"home--view",
"network--view",
"tree--view",
"warnings--view"
];
const kAlwaysVisibleMenus = [
"search--view",
"settings--view"
];

test.describe("[navigation] with data", () => {
test.beforeEach(async({ page }) => {
await page.goto("/");
await page.waitForSelector(`[data-menu="network--view"].active`);
});

test("all tabs are visible in the sidebar", async({ page }) => {
for (const menu of [...kDataMenus, ...kAlwaysVisibleMenus]) {
await expect(page.locator(`[data-menu="${menu}"]`)).not.toContainClass("hidden");
}
});

test("network view is active by default", async({ page }) => {
await expect(page.locator("#network--view")).not.toContainClass("hidden");
await expect(page.locator(`[data-menu="network--view"]`)).toContainClass("active");
});

test("clicking the settings tab shows the settings view", async({ page }) => {
await page.locator(`[data-menu="settings--view"]`).click();

await expect(page.locator("#settings--view")).not.toContainClass("hidden");
await expect(page.locator("#network--view")).toContainClass("hidden");
});

test("pressing S navigates to the settings view", async({ page }) => {
await page.keyboard.press("s");

await expect(page.locator("#settings--view")).not.toContainClass("hidden");
});

test("pressing A navigates to the warnings view", async({ page }) => {
await page.keyboard.press("a");

await expect(page.locator("#warnings--view")).not.toContainClass("hidden");
});
});

test.describe("[navigation] without data", () => {
test.beforeEach(async({ page }) => {
await page.route("**/data", (route) => route.fulfill({ status: 204 }));
await page.goto("/");
await page.waitForSelector(`[data-menu="search--view"].active`);
});

test("data-dependent tabs are hidden in the sidebar", async({ page }) => {
for (const menu of kDataMenus) {
await expect(page.locator(`[data-menu="${menu}"]`)).toContainClass("hidden");
}
});

test("always visible menus tabs remain visible", async({ page }) => {
for (const menu of kAlwaysVisibleMenus) {
await expect(page.locator(`[data-menu="${menu}"]`)).not.toContainClass("hidden");
}
});

test("search view is the active view", async({ page }) => {
await expect(page.locator("#search--view")).not.toContainClass("hidden");
await expect(page.locator(`[data-menu="search--view"]`)).toContainClass("active");
});
});
Loading
Loading