Files
fusion/scripts/__tests__/ios-acceptance.test.mjs
gsxdsm deb1717812 FN-6667: add real iOS Safari acceptance harness
Add a real iOS Safari acceptance harness and documentation for terminal verification gates.

- Add an `ios:acceptance` script with check, dry-run, and real WebDriver session modes.
- Support BrowserStack, Sauce Labs, and LambdaTest credential discovery with redacted capability planning.
- Document the real-iOS provisioning workflow and link it from testing docs.
- Cover credential selection, URL validation, capability shaping, and CLI behavior with node tests.

Files changed:
 docs/README.md                            |   1 +
 docs/ios-acceptance.md                    | 144 ++++++++++++++++
 docs/testing.md                           |   3 +
 package.json                              |   1 +
 scripts/__tests__/ios-acceptance.test.mjs | 131 +++++++++++++++
 scripts/ios-acceptance.mjs                | 264 ++++++++++++++++++++++++++++++
 scripts/lib/ios-acceptance.mjs            | 243 +++++++++++++++++++++++++++
 7 files changed, 787 insertions(+)

Fusion-Task-Id: FN-6667

Fusion-Task-Lineage: 9eee6dbe-646e-4fff-a1da-fd59cdd2cb59
2026-06-18 16:47:09 -07:00

132 lines
4.6 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
buildIosCapabilities,
describeAvailability,
iosHubUrl,
redactUrl,
resolveIosProvider,
} from "../lib/ios-acceptance.mjs";
const allCredentials = {
BROWSERSTACK_USERNAME: "browserstack-user",
BROWSERSTACK_ACCESS_KEY: "browserstack-key",
SAUCE_USERNAME: "sauce-user",
SAUCE_ACCESS_KEY: "sauce-key",
LT_USERNAME: "lt-user",
LT_ACCESS_KEY: "lt-key",
};
test("resolveIosProvider follows BrowserStack, Sauce, LambdaTest precedence", () => {
assert.equal(resolveIosProvider(allCredentials), "browserstack");
assert.equal(
resolveIosProvider({
SAUCE_USERNAME: "sauce-user",
SAUCE_ACCESS_KEY: "sauce-key",
}),
"sauce",
);
assert.equal(
resolveIosProvider({
LT_USERNAME: "lt-user",
LT_ACCESS_KEY: "lt-key",
}),
"lambdatest",
);
assert.equal(resolveIosProvider({}), null);
});
test("resolveIosProvider treats whitespace-only credential values as absent", () => {
assert.equal(
resolveIosProvider({
BROWSERSTACK_USERNAME: "browserstack-user",
BROWSERSTACK_ACCESS_KEY: " ",
SAUCE_USERNAME: "\t",
SAUCE_ACCESS_KEY: "sauce-key",
LT_USERNAME: "lt-user",
LT_ACCESS_KEY: "\n",
}),
null,
);
});
test("describeAvailability enumerates checked and missing keys without secret values", () => {
const availability = describeAvailability({});
assert.equal(availability.available, false);
assert.equal(availability.provider, null);
assert.deepEqual(availability.checkedKeys, [
"BROWSERSTACK_USERNAME",
"BROWSERSTACK_ACCESS_KEY",
"SAUCE_USERNAME",
"SAUCE_ACCESS_KEY",
"LT_USERNAME",
"LT_ACCESS_KEY",
]);
assert.deepEqual(availability.missing, availability.checkedKeys);
const withSecrets = describeAvailability(allCredentials);
const serialized = JSON.stringify(withSecrets);
for (const value of Object.values(allCredentials)) {
assert.equal(serialized.includes(value), false, `availability leaked credential value ${value}`);
}
});
test("buildIosCapabilities creates real iOS Safari capabilities for each provider", () => {
const browserstack = buildIosCapabilities("browserstack", {
deviceName: "iPhone 14",
platformVersion: "16",
});
assert.equal(browserstack.browserName, "safari");
assert.equal(browserstack.platformName, "iOS");
assert.equal(browserstack["bstack:options"].deviceName, "iPhone 14");
assert.equal(browserstack["bstack:options"].osVersion, "16");
assert.equal(browserstack["bstack:options"].realMobile, true);
const sauce = buildIosCapabilities("sauce", {
deviceName: "iPhone 15 Pro",
platformVersion: "17",
});
assert.equal(sauce.browserName, "safari");
assert.equal(sauce.platformName, "iOS");
assert.equal(sauce["appium:deviceName"], "iPhone 15 Pro");
assert.equal(sauce["appium:platformVersion"], "17");
assert.equal(sauce["sauce:options"].realDevice, true);
const lambdatest = buildIosCapabilities("lambdatest", {
deviceName: "iPhone 13",
platformVersion: "15",
});
assert.equal(lambdatest.browserName, "safari");
assert.equal(lambdatest.platformName, "iOS");
assert.equal(lambdatest["LT:Options"].deviceName, "iPhone 13");
assert.equal(lambdatest["LT:Options"].platformVersion, "15");
assert.equal(lambdatest["LT:Options"].isRealMobile, true);
});
test("iosHubUrl uses provider defaults, env overrides, and redacts embedded credentials", () => {
const browserstackUrl = iosHubUrl(
"browserstack",
{ username: "user@example.com", accessKey: "browserstack-secret" },
{},
);
assert.equal(browserstackUrl, "https://user%40example.com:browserstack-secret@hub-cloud.browserstack.com/wd/hub");
const sauceUrl = iosHubUrl("sauce", { username: "sauce-user", accessKey: "sauce-secret" }, {});
assert.equal(sauceUrl, "https://sauce-user:sauce-secret@ondemand.us-west-1.saucelabs.com/wd/hub");
const ltUrl = iosHubUrl("lambdatest", { username: "lt-user", accessKey: "lt-secret" }, {});
assert.equal(ltUrl, "https://lt-user:lt-secret@mobile-hub.lambdatest.com/wd/hub");
const overrideUrl = iosHubUrl(
"browserstack",
{ username: "override-user", accessKey: "override-secret" },
{ BROWSERSTACK_HUB_URL: "https://example.test/custom/wd/hub" },
);
assert.equal(overrideUrl, "https://override-user:override-secret@example.test/custom/wd/hub");
const redacted = redactUrl(overrideUrl);
assert.equal(redacted, "https://<redacted>:<redacted>@example.test/custom/wd/hub");
assert.equal(redacted.includes("override-user"), false);
assert.equal(redacted.includes("override-secret"), false);
});