101 lines
4.6 KiB
TypeScript
101 lines
4.6 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { generateMobile, mobileOptions } from "../src/mobile.ts";
|
|
import { runMobileCommand } from "../src/mobile-command.ts";
|
|
import { nativeCatalog, runNativeCommand } from "../src/native-command.ts";
|
|
|
|
test("generateMobile scaffolds a configurable Capacitor project", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "wrn-mobile-"));
|
|
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "@acme/store-front" }));
|
|
|
|
await generateMobile(dir, {
|
|
appId: "com.acme.store",
|
|
appName: "Acme Store",
|
|
serverUrl: "https://store.example.com",
|
|
});
|
|
|
|
const config = readFileSync(join(dir, "mobile", "capacitor.config.ts"), "utf8");
|
|
expect(config).toContain('appId: mobile.appId ?? "com.acme.store"');
|
|
expect(config).toContain('appName: mobile.appName ?? "Acme Store"');
|
|
expect(config).toContain("...(mobile.capacitor ?? {})");
|
|
expect(config).not.toContain("errorPath:");
|
|
expect(config).toContain('"https://store.example.com"');
|
|
expect(existsSync(join(dir, "mobile", "web", "index.html"))).toBe(true);
|
|
|
|
const pkg = JSON.parse(readFileSync(join(dir, "mobile", "package.json"), "utf8"));
|
|
expect(pkg.dependencies["@capacitor/android"]).toBe("^8.0.0");
|
|
expect(pkg.scripts["open:ios"]).toBe("cap open ios");
|
|
});
|
|
|
|
test("generateMobile derives defaults and does not overwrite files", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "wrn-mobile-"));
|
|
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "demo-app" }));
|
|
await generateMobile(dir);
|
|
const path = join(dir, "mobile", "capacitor.config.ts");
|
|
const before = readFileSync(path, "utf8");
|
|
expect(before).toContain('appId: mobile.appId ?? "com.example.demoapp"');
|
|
expect(before).toContain('"http://localhost:3000"');
|
|
await generateMobile(dir, { appName: "Changed" });
|
|
expect(readFileSync(path, "utf8")).toBe(before);
|
|
});
|
|
|
|
test("mobileOptions parses generator flags", () => {
|
|
expect(
|
|
mobileOptions(["--app-id=com.acme.app", "--app-name=Acme", "--url=https://app.test"]),
|
|
).toEqual({
|
|
appId: "com.acme.app",
|
|
appName: "Acme",
|
|
serverUrl: "https://app.test",
|
|
mode: undefined,
|
|
});
|
|
});
|
|
|
|
test("generateMobile scaffolds a WebView-free native project from config", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "wrn-native-"));
|
|
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "native-demo" }));
|
|
writeFileSync(
|
|
join(dir, "wrnexus.config.mjs"),
|
|
`export default { mobile: { mode: "native", appId: "com.acme.native", apiUrl: "https://api.example.com" } }`,
|
|
);
|
|
await generateMobile(dir);
|
|
const pkg = JSON.parse(readFileSync(join(dir, "mobile", "package.json"), "utf8"));
|
|
expect(pkg.wrnexus.mode).toBe("native");
|
|
expect(pkg.dependencies.expo).toBeDefined();
|
|
expect(existsSync(join(dir, "mobile", "app", "index.tsx"))).toBe(true);
|
|
expect(readFileSync(join(dir, "mobile", "src", "wrnexus.ts"), "utf8")).toContain(
|
|
"https://api.example.com",
|
|
);
|
|
expect(existsSync(join(dir, "mobile", "capacitor.config.ts"))).toBe(false);
|
|
});
|
|
|
|
test("mobile compile turns wrn pages into Expo routes", async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), "wrn-native-compile-"));
|
|
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "native-compile" }));
|
|
writeFileSync(join(dir, "wrnexus.config.mjs"), `export default { mobile: { mode: "native" } }`);
|
|
await generateMobile(dir);
|
|
const pages = join(dir, "app", "pages");
|
|
const nested = join(pages, "account");
|
|
mkdirSync(nested, { recursive: true });
|
|
writeFileSync(
|
|
join(nested, "profile.wrn"),
|
|
"page Profile { view { <main><h1>Profile</h1></main> } }",
|
|
);
|
|
await runMobileCommand(dir, "compile");
|
|
const output = readFileSync(join(dir, "mobile", "app", "account", "profile.tsx"), "utf8");
|
|
expect(output).toContain("function Profile()");
|
|
expect(output).toContain("<View><Text>Profile</Text></View>");
|
|
});
|
|
|
|
test("native catalog uses built-in React Native sharing without installing expo-sharing", async () => {
|
|
expect(nativeCatalog.share?.expo).toBeUndefined();
|
|
const dir = mkdtempSync(join(tmpdir(), "wrn-native-share-"));
|
|
writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "native-share" }));
|
|
writeFileSync(join(dir, "wrnexus.config.mjs"), `export default { mobile: { mode: "native" } }`);
|
|
await generateMobile(dir);
|
|
await runNativeCommand(dir, "add", ["share"]);
|
|
const pkg = JSON.parse(readFileSync(join(dir, "mobile", "package.json"), "utf8"));
|
|
expect(pkg.dependencies["expo-sharing"]).toBeUndefined();
|
|
});
|