Editors now take document TipTap nodes from a shared factory. Workspace and editor helpers move out of the large panes. Store iOS no longer builds from Expo EAS.
216 lines
7.6 KiB
JavaScript
216 lines
7.6 KiB
JavaScript
import { describe, expect, test } from "bun:test";
|
|
import { readFileSync } from "node:fs";
|
|
import { parseStoreDeliveryArgs } from "./store-delivery.mjs";
|
|
|
|
describe("store delivery command", () => {
|
|
test("uses full production delivery defaults", () => {
|
|
expect(parseStoreDeliveryArgs(["--release", "v1.7.0"])).toMatchObject({
|
|
releaseTag: "v1.7.0",
|
|
platform: "both",
|
|
androidTrack: "production",
|
|
});
|
|
});
|
|
|
|
test("accepts an explicit single platform", () => {
|
|
expect(
|
|
parseStoreDeliveryArgs(["--release", "v1.7.0", "--platform", "ios"])
|
|
.platform,
|
|
).toBe("ios");
|
|
});
|
|
|
|
test("supports recovering a Play-signed APK without re-uploading", () => {
|
|
expect(
|
|
parseStoreDeliveryArgs([
|
|
"--release",
|
|
"v1.7.0",
|
|
"--platform",
|
|
"android",
|
|
"--recover-play-apk",
|
|
]).recoverPlayApk,
|
|
).toBe(true);
|
|
});
|
|
|
|
test("supports submitting an existing iOS build without rebuilding", () => {
|
|
expect(
|
|
parseStoreDeliveryArgs([
|
|
"--release",
|
|
"v1.7.0",
|
|
"--platform",
|
|
"ios",
|
|
"--ios-build-number",
|
|
"30",
|
|
]).iosBuildNumber,
|
|
).toBe("30");
|
|
});
|
|
|
|
test("rejects malformed release tags", () => {
|
|
expect(() => parseStoreDeliveryArgs(["--release", "latest"])).toThrow(
|
|
"stable vX.Y.Z",
|
|
);
|
|
});
|
|
|
|
test("uses the pinned official EAS CLI setup in store jobs", () => {
|
|
const workflow = readFileSync(
|
|
new URL("../.github/workflows/store-delivery.yml", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
expect(workflow).not.toContain("bunx eas-cli");
|
|
expect(workflow.match(/uses: expo\/expo-github-action@v8/g)).toHaveLength(
|
|
1,
|
|
);
|
|
expect(workflow.match(/eas-version: 21\.4\.0/g)).toHaveLength(1);
|
|
expect(workflow.match(/packager: npm/g)).toHaveLength(1);
|
|
expect(workflow).toContain("for attempt in 1 2 3");
|
|
expect(workflow).toContain("Dependency install failed on attempt ${attempt}/3");
|
|
expect(
|
|
workflow.match(
|
|
/edgeever-bun-cache-\$\{GITHUB_RUN_ID\}-\$\{GITHUB_RUN_ATTEMPT\}/g,
|
|
),
|
|
).toHaveLength(2);
|
|
expect(workflow).not.toContain("eas build");
|
|
expect(workflow).not.toContain("--platform ios");
|
|
expect(workflow).toContain("working-directory: apps/ios");
|
|
expect(workflow).toContain(
|
|
"APP_STORE_BUILD_NUMBER: ${{ inputs.ios_build_number }}",
|
|
);
|
|
expect(workflow).toContain(
|
|
"APP_STORE_CONNECT_API_ISSUER_ID: ${{ secrets.EDGEEVER_APPLE_API_ISSUER }}",
|
|
);
|
|
expect(workflow).toContain(
|
|
"APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.EDGEEVER_APPLE_API_KEY_ID }}",
|
|
);
|
|
expect(workflow).toContain(
|
|
"APP_STORE_CONNECT_API_KEY_P8_BASE64: ${{ secrets.EDGEEVER_APPLE_API_KEY_BASE64 }}",
|
|
);
|
|
expect(workflow).toContain(
|
|
'PRECHECK_INCLUDE_IN_APP_PURCHASES: "false"',
|
|
);
|
|
expect(workflow).toContain("for attempt in {1..20}");
|
|
expect(workflow).toContain(
|
|
'Build number: ${APP_STORE_BUILD_NUMBER} does not exist',
|
|
);
|
|
expect(workflow).toContain("retrying in 60 seconds (${attempt}/20)");
|
|
const fastfile = readFileSync(
|
|
new URL("../apps/ios/fastlane/Fastfile", import.meta.url),
|
|
"utf8",
|
|
);
|
|
expect(fastfile).toContain("precheck_include_in_app_purchases: false");
|
|
});
|
|
|
|
test("replaces the GitHub APK with the Play-signed universal APK", () => {
|
|
const workflow = readFileSync(
|
|
new URL("../.github/workflows/store-delivery.yml", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
expect(workflow).toContain("GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64");
|
|
expect(workflow).toContain("ANDROID_PLAY_APP_SIGNER_SHA256");
|
|
expect(workflow).toContain("scripts/download-play-universal-apk.mjs");
|
|
expect(workflow).toContain('gh release upload "$RELEASE_TAG" "$apk_path"');
|
|
expect(
|
|
workflow.match(/if: \$\{\{ !inputs\.recover_play_apk \}\}/g),
|
|
).toHaveLength(6);
|
|
expect(workflow).toContain("if: ${{ inputs.recover_play_apk }}");
|
|
expect(workflow).toContain(
|
|
"node --input-type=module -e \"await import('google-auth-library')\"",
|
|
);
|
|
});
|
|
|
|
test("can prepare a matching Draft before formal publication", () => {
|
|
const workflow = readFileSync(
|
|
new URL("../.github/workflows/store-delivery.yml", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
expect(workflow).toContain('if [[ "$release_is_draft" = "true" ]]');
|
|
expect(workflow).toContain('previous_tag="${release_tags[0]:-}"');
|
|
expect(workflow).toContain('git tag "$RELEASE_TAG" "$RELEASE_TARGET"');
|
|
expect(workflow).toContain("set -o pipefail");
|
|
expect(workflow).toContain(
|
|
"release_target: ${{ steps.release.outputs.release_target }}",
|
|
);
|
|
expect(workflow).toContain('gh release view "$RELEASE_TAG"');
|
|
expect(workflow).not.toContain("releases/tags/${RELEASE_TAG}");
|
|
expect(workflow).toContain(
|
|
"ref: ${{ steps.release.outputs.release_target }}",
|
|
);
|
|
expect(
|
|
workflow.match(/ref: \$\{\{ needs\.plan\.outputs\.release_target \}\}/g),
|
|
).toHaveLength(2);
|
|
expect(workflow).not.toContain("ref: ${{ inputs.release_tag }}");
|
|
expect(workflow).not.toContain(
|
|
'test "$(jq -r \'.draft\' <<<"$release")" = "false"',
|
|
);
|
|
});
|
|
|
|
test("uses a dedicated Draft audit that accepts only the Play app signer", () => {
|
|
const workflow = readFileSync(
|
|
new URL(
|
|
"../.github/workflows/android-play-signature-audit.yml",
|
|
import.meta.url,
|
|
),
|
|
"utf8",
|
|
);
|
|
|
|
expect(workflow).toContain("github.repository == 'tianma-if/edgeever'");
|
|
expect(workflow).toContain(
|
|
"permissions:\n # Draft Releases are only visible to a token with repository write access.\n contents: write",
|
|
);
|
|
expect(workflow).toContain('gh release view "$RELEASE_TAG"');
|
|
expect(workflow).toContain(
|
|
'test "$(jq -r \'.isDraft\' <<<"$release")" = "true"',
|
|
);
|
|
expect(workflow).toContain(
|
|
"ref: ${{ steps.release.outputs.target_commitish }}",
|
|
);
|
|
expect(workflow).not.toContain("ref: ${{ inputs.release_tag }}");
|
|
expect(workflow).toContain(
|
|
"EDGE_EVER_ANDROID_ALLOWED_SIGNER_SHA256: ${{ secrets.ANDROID_PLAY_APP_SIGNER_SHA256 }}",
|
|
);
|
|
expect(workflow).not.toContain(
|
|
"22bf52a9501c89020f5acc966960152c826bfa64f31e578e858d088f8cd75d87",
|
|
);
|
|
});
|
|
|
|
test("keeps the Play bundle and generated Release APK arm64-only", () => {
|
|
const workflow = readFileSync(
|
|
new URL("../.github/workflows/store-delivery.yml", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const buildScript = readFileSync(
|
|
new URL("./build-android-local.sh", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
expect(workflow).toContain("EDGE_EVER_ANDROID_PLAY_ARCHS: arm64-v8a");
|
|
expect(workflow).toContain("Verify Play APK architecture");
|
|
expect(workflow).toContain('if [[ "$actual_archs" != "arm64-v8a" ]]');
|
|
expect(buildScript).toContain(
|
|
'PLAY_ARCHS="${EDGE_EVER_ANDROID_PLAY_ARCHS:-arm64-v8a}"',
|
|
);
|
|
expect(buildScript).toContain(
|
|
'if [[ "$ACTUAL_PLAY_ARCHS" != "$PLAY_ARCHS" ]]',
|
|
);
|
|
expect(buildScript).not.toContain("EDGE_EVER_ANDROID_ARCHS:-");
|
|
expect(buildScript).not.toContain("armeabi-v7a,arm64-v8a,x86,x86_64");
|
|
});
|
|
|
|
test("keeps the self-update install permission out of Android builds", () => {
|
|
const buildScript = readFileSync(
|
|
new URL("./build-android-local.sh", import.meta.url),
|
|
"utf8",
|
|
);
|
|
const appConfig = readFileSync(
|
|
new URL("../apps/mobile/app.json", import.meta.url),
|
|
"utf8",
|
|
);
|
|
|
|
expect(appConfig).not.toContain("android.permission.REQUEST_INSTALL_PACKAGES");
|
|
expect(buildScript).not.toContain("configure-android-package-permissions");
|
|
expect(buildScript).toContain(
|
|
'grep -q "android.permission.REQUEST_INSTALL_PACKAGES" "$PACKAGED_MANIFEST"',
|
|
);
|
|
});
|
|
});
|