@jskit-ai/create-app 0.1.133 → 0.1.134
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/server/index.js +3 -4
- package/templates/base-shell/.jskit/lock.json +7 -1
- package/templates/base-shell/playwright.config.mjs +4 -0
- package/templates/base-shell/tests/e2e/base-shell.spec.ts +2 -55
- package/templates/minimal-shell/playwright.config.mjs +4 -0
- package/templates/minimal-shell/tests/e2e/base-shell.spec.ts +2 -55
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/create-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.134",
|
|
4
4
|
"description": "Scaffold JSKIT app shells.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"./client": "./src/client/index.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@jskit-ai/jskit-cli": "0.2.
|
|
23
|
+
"@jskit-ai/jskit-cli": "0.2.137"
|
|
24
24
|
},
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": "^22.12.0 || ^24.0.0 || ^26.0.0"
|
package/src/server/index.js
CHANGED
|
@@ -16,7 +16,6 @@ const DEFAULT_INITIAL_BUNDLES = "none";
|
|
|
16
16
|
const DEFAULT_PLAYWRIGHT_VERSION = "1.61.1";
|
|
17
17
|
const INITIAL_BUNDLE_PRESETS = new Set(["none", "auth"]);
|
|
18
18
|
const TENANCY_MODES = new Set(["none", "personal", "workspaces"]);
|
|
19
|
-
const EXACT_SEMVER_PATTERN = /^\d+\.\d+\.\d+$/u;
|
|
20
19
|
const ALLOWED_EXISTING_TARGET_ENTRIES = new Set([".git"]);
|
|
21
20
|
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
22
21
|
const TEMPLATES_ROOT = path.join(PACKAGE_ROOT, "templates");
|
|
@@ -57,12 +56,12 @@ function normalizeTenancyMode(value, { showUsage = true } = {}) {
|
|
|
57
56
|
|
|
58
57
|
function normalizePlaywrightVersion(value, { showUsage = true } = {}) {
|
|
59
58
|
const normalized = String(value || "").trim();
|
|
60
|
-
if (
|
|
59
|
+
if (normalized === DEFAULT_PLAYWRIGHT_VERSION) {
|
|
61
60
|
return normalized;
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
throw createCliError(
|
|
65
|
-
`Invalid --playwright-version value "${value}".
|
|
64
|
+
`Invalid --playwright-version value "${value}". JSKIT requires ${DEFAULT_PLAYWRIGHT_VERSION}.`,
|
|
66
65
|
{ showUsage }
|
|
67
66
|
);
|
|
68
67
|
}
|
|
@@ -262,7 +261,7 @@ function printUsage(stream = process.stderr) {
|
|
|
262
261
|
stream.write(" --title <text> App title used for template replacements\n");
|
|
263
262
|
stream.write(" --target <path> Target directory (default: ./<app-name>)\n");
|
|
264
263
|
stream.write(" --initial-bundles <preset> Optional initial setup preset: none | auth (default: none)\n");
|
|
265
|
-
stream.write(` --playwright-version <
|
|
264
|
+
stream.write(` --playwright-version <version> Supported Playwright test version (${DEFAULT_PLAYWRIGHT_VERSION})\n`);
|
|
266
265
|
stream.write(" --tenancy-mode <mode> Optional config seed: none | personal | workspaces\n");
|
|
267
266
|
stream.write(" --force Allow writing into a non-empty target directory\n");
|
|
268
267
|
stream.write(" --dry-run Print planned writes without changing the filesystem\n");
|
|
@@ -48,7 +48,13 @@
|
|
|
48
48
|
"value": "0.x"
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
|
-
"devDependencies": {
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@playwright/test": {
|
|
53
|
+
"hadPrevious": true,
|
|
54
|
+
"previousValue": "__PLAYWRIGHT_VERSION__",
|
|
55
|
+
"value": "__PLAYWRIGHT_VERSION__"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
52
58
|
"scripts": {}
|
|
53
59
|
},
|
|
54
60
|
"text": {
|
|
@@ -1,57 +1,4 @@
|
|
|
1
1
|
import { expect, test } from "@playwright/test";
|
|
2
|
+
import { runGeneratedAppSmoke } from "@jskit-ai/jskit-cli/test/playwright";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const SMOKE_PATH = String(process.env.JSKIT_PLAYWRIGHT_SMOKE_PATH || "/home");
|
|
5
|
-
|
|
6
|
-
const viewports = [
|
|
7
|
-
{ name: "compact", width: 390, height: 844 },
|
|
8
|
-
{ name: "medium", width: 768, height: 1024 },
|
|
9
|
-
{ name: "expanded", width: 1280, height: 900 }
|
|
10
|
-
];
|
|
11
|
-
|
|
12
|
-
async function expectNoHorizontalOverflow(page) {
|
|
13
|
-
const metrics = await page.evaluate(() => ({
|
|
14
|
-
clientWidth: document.documentElement.clientWidth,
|
|
15
|
-
scrollWidth: document.documentElement.scrollWidth
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
expect(metrics.scrollWidth).toBeLessThanOrEqual(metrics.clientWidth + 1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function expectGeneratedScreenContract(page) {
|
|
22
|
-
const screen = page.locator(".generated-ui-screen").first();
|
|
23
|
-
|
|
24
|
-
await expect(screen).toBeVisible();
|
|
25
|
-
await expect(screen).toHaveClass(/generated-ui-screen--app/u);
|
|
26
|
-
await expect(screen.locator("h1").first()).toBeVisible();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function expectVisibleTapTargets(page) {
|
|
30
|
-
const targetHeights = await page.locator("a[href], button, [role='button'], .v-btn, .v-list-item").evaluateAll(
|
|
31
|
-
(elements) => elements
|
|
32
|
-
.filter((element) => {
|
|
33
|
-
const rect = element.getBoundingClientRect();
|
|
34
|
-
const style = window.getComputedStyle(element);
|
|
35
|
-
return style.display !== "none" && style.visibility !== "hidden" && rect.width > 0 && rect.height > 0;
|
|
36
|
-
})
|
|
37
|
-
.map((element) => element.getBoundingClientRect().height)
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
for (const height of targetHeights) {
|
|
41
|
-
expect(height).toBeGreaterThanOrEqual(48);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
test.describe("generated base app responsive smoke", () => {
|
|
46
|
-
for (const viewport of viewports) {
|
|
47
|
-
test(`${viewport.name} home route renders without horizontal overflow`, async ({ page }) => {
|
|
48
|
-
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
|
49
|
-
await page.goto(`${BASE_URL}${SMOKE_PATH}`);
|
|
50
|
-
await expect(page.locator("body")).toBeVisible();
|
|
51
|
-
await expect(page.getByText("Ready")).toBeVisible();
|
|
52
|
-
await expectGeneratedScreenContract(page);
|
|
53
|
-
await expectVisibleTapTargets(page);
|
|
54
|
-
await expectNoHorizontalOverflow(page);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
});
|
|
4
|
+
runGeneratedAppSmoke({ test, expect, expectedText: "Ready" });
|
|
@@ -1,57 +1,4 @@
|
|
|
1
1
|
import { expect, test } from "@playwright/test";
|
|
2
|
+
import { runGeneratedAppSmoke } from "@jskit-ai/jskit-cli/test/playwright";
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const SMOKE_PATH = String(process.env.JSKIT_PLAYWRIGHT_SMOKE_PATH || "/home");
|
|
5
|
-
|
|
6
|
-
const viewports = [
|
|
7
|
-
{ name: "compact", width: 390, height: 844 },
|
|
8
|
-
{ name: "medium", width: 768, height: 1024 },
|
|
9
|
-
{ name: "expanded", width: 1280, height: 900 }
|
|
10
|
-
];
|
|
11
|
-
|
|
12
|
-
async function expectNoHorizontalOverflow(page) {
|
|
13
|
-
const metrics = await page.evaluate(() => ({
|
|
14
|
-
clientWidth: document.documentElement.clientWidth,
|
|
15
|
-
scrollWidth: document.documentElement.scrollWidth
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
expect(metrics.scrollWidth).toBeLessThanOrEqual(metrics.clientWidth + 1);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function expectGeneratedScreenContract(page) {
|
|
22
|
-
const screen = page.locator(".generated-ui-screen").first();
|
|
23
|
-
|
|
24
|
-
await expect(screen).toBeVisible();
|
|
25
|
-
await expect(screen).toHaveClass(/generated-ui-screen--app/u);
|
|
26
|
-
await expect(screen.locator("h1").first()).toBeVisible();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function expectVisibleTapTargets(page) {
|
|
30
|
-
const targetHeights = await page.locator("a[href], button, [role='button'], .v-btn, .v-list-item").evaluateAll(
|
|
31
|
-
(elements) => elements
|
|
32
|
-
.filter((element) => {
|
|
33
|
-
const rect = element.getBoundingClientRect();
|
|
34
|
-
const style = window.getComputedStyle(element);
|
|
35
|
-
return style.display !== "none" && style.visibility !== "hidden" && rect.width > 0 && rect.height > 0;
|
|
36
|
-
})
|
|
37
|
-
.map((element) => element.getBoundingClientRect().height)
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
for (const height of targetHeights) {
|
|
41
|
-
expect(height).toBeGreaterThanOrEqual(48);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
test.describe("generated base app responsive smoke", () => {
|
|
46
|
-
for (const viewport of viewports) {
|
|
47
|
-
test(`${viewport.name} home route renders without horizontal overflow`, async ({ page }) => {
|
|
48
|
-
await page.setViewportSize({ width: viewport.width, height: viewport.height });
|
|
49
|
-
await page.goto(`${BASE_URL}${SMOKE_PATH}`);
|
|
50
|
-
await expect(page.locator("body")).toBeVisible();
|
|
51
|
-
await expect(page.getByText("Home base")).toBeVisible();
|
|
52
|
-
await expectGeneratedScreenContract(page);
|
|
53
|
-
await expectVisibleTapTargets(page);
|
|
54
|
-
await expectNoHorizontalOverflow(page);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
});
|
|
4
|
+
runGeneratedAppSmoke({ test, expect, expectedText: "Home base" });
|