@specific.dev/spectest 0.126.0 → 0.128.0

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.
Files changed (46) hide show
  1. package/dist/android-step.d.ts +7 -0
  2. package/dist/android.d.ts +17 -3
  3. package/dist/android.js +122 -26
  4. package/dist/components/android.d.ts +1 -1
  5. package/dist/components/android.js +1 -1
  6. package/dist/components/k3s-coverage.d.ts +24 -0
  7. package/dist/components/k3s-coverage.js +259 -0
  8. package/dist/components/k3s-trust.d.ts +4 -2
  9. package/dist/components/k3s-trust.js +13 -0
  10. package/dist/components/k3s.js +31 -0
  11. package/dist/coverage/rust.rs +102 -0
  12. package/dist/coverage-bun.d.ts +10 -0
  13. package/dist/coverage-bun.js +32 -0
  14. package/dist/coverage-rust.d.ts +23 -0
  15. package/dist/coverage-rust.js +71 -0
  16. package/dist/coverage.d.ts +11 -5
  17. package/dist/coverage.js +70 -13
  18. package/dist/daemon.js +27 -2
  19. package/dist/harness/component-images.d.ts +1 -0
  20. package/dist/harness/component-images.js +4 -2
  21. package/dist/harness/coverage-target.d.ts +10 -0
  22. package/dist/harness/coverage-target.js +54 -0
  23. package/dist/index.d.ts +21 -1
  24. package/dist/index.js +34 -1
  25. package/package.json +1 -1
  26. package/src/android-actions.test.ts +121 -0
  27. package/src/android-step.ts +2 -0
  28. package/src/android.test.ts +3 -0
  29. package/src/android.ts +107 -33
  30. package/src/components/android.test.ts +1 -0
  31. package/src/components/android.ts +2 -2
  32. package/src/components/k3s-coverage.test.ts +160 -0
  33. package/src/components/k3s-coverage.ts +234 -0
  34. package/src/components/k3s-trust.ts +14 -2
  35. package/src/components/k3s.ts +26 -0
  36. package/src/coverage/rust.rs +102 -0
  37. package/src/coverage-bun.test.ts +103 -0
  38. package/src/coverage-bun.ts +40 -0
  39. package/src/coverage-rust.test.ts +74 -0
  40. package/src/coverage-rust.ts +79 -0
  41. package/src/coverage.test.ts +4 -4
  42. package/src/coverage.ts +74 -13
  43. package/src/daemon.ts +22 -2
  44. package/src/harness/component-images.ts +5 -2
  45. package/src/harness/coverage-target.ts +55 -0
  46. package/src/index.ts +44 -4
package/src/index.ts CHANGED
@@ -6,7 +6,7 @@ import type { InjectRule, SignConfig } from "./fake-upstream.js";
6
6
  export type { InjectRule, InjectMatch, StringMatch, SignConfig, AwsSigV4Sign } from "./fake-upstream.js";
7
7
  export type { Phone, PhoneOptions, CallOptions, SpeechOptions } from "./phone.js";
8
8
  import type { Phone, PhoneOptions } from "./phone.js";
9
- import type { Android, AndroidApp } from "./android.js";
9
+ import { ANDROID_ASSERT, type Android, type AndroidApp, type AndroidElement, type AndroidMatcher } from "./android.js";
10
10
  import { resolveEntrypoints, type InteractiveEntrypoint, type InteractiveEntrypoints } from "./interactive.js";
11
11
  export type { InteractiveEntrypoint, InteractiveEntrypoints } from "./interactive.js";
12
12
  export type { Android, AndroidApp, AndroidElement, AndroidRecordingOptions } from "./android.js";
@@ -175,7 +175,7 @@ export {
175
175
  type CoverageLoadContext,
176
176
  type ServiceCoverage,
177
177
  } from "./coverage.js";
178
- import { applyCoverageAdapters, validateCoverage, type ServiceCoverage } from "./coverage.js";
178
+ import { applyCoverageAdapters, coverageAdapters, validateCoverage, type ServiceCoverage } from "./coverage.js";
179
179
  import { resolveExistingProjectPath } from "./project-files.js";
180
180
  export { ca } from "./environment-ca.js";
181
181
 
@@ -1138,6 +1138,15 @@ function expandServiceGroups(input: InputServicesMap): ServicesMap {
1138
1138
  // Rewrite relative dependsOn to final keys; a spread keeps function
1139
1139
  // fields (helpers/setup) and the enumerable-symbol ingress decls.
1140
1140
  const final: ServiceConfig = { ...svc, ...(part === entry.primary ? primaryOverrides : {}) };
1141
+ // Component-owned nested containers keep their collection when callers
1142
+ // add ordinary service coverage (for example browser coverage on k3s).
1143
+ const collectors = coverageAdapters(svc.coverage).filter(adapter => adapter.collect);
1144
+ if (part === entry.primary && collectors.length && primaryOverrides.coverage !== undefined) {
1145
+ const extra = primaryOverrides.coverage;
1146
+ final.coverage = { ...(typeof extra === "object" ? extra : {}), adapters: [
1147
+ ...collectors, ...coverageAdapters(extra).filter(adapter => !collectors.includes(adapter)),
1148
+ ] };
1149
+ }
1141
1150
  if (final.dependsOn?.length) {
1142
1151
  final.dependsOn = final.dependsOn.map((d) =>
1143
1152
  partKeys.has(d) ? naming.key(d) : d,
@@ -3030,18 +3039,49 @@ export interface BrowserAssertion extends BrowserMatchers {
3030
3039
  // `expect(value)` the synchronous value matchers. The two object overloads are
3031
3040
  // listed first so they win over `Provenanced` (neither has `unwrap`); a
3032
3041
  // Locator and a Browser are structurally disjoint, so their order is free.
3042
+ export function expect(actual: AndroidElement, message?: string): AndroidAssertion;
3033
3043
  export function expect(actual: Locator, message?: string): LocatorAssertion;
3034
3044
  export function expect(actual: Browser, message?: string): BrowserAssertion;
3035
3045
  export function expect(actual: Provenanced, message?: string): Expectation;
3036
3046
  export function expect(
3037
- actual: Provenanced | Locator | Browser,
3047
+ actual: Provenanced | Locator | Browser | AndroidElement,
3038
3048
  message?: string,
3039
- ): Expectation | LocatorAssertion | BrowserAssertion {
3049
+ ): Expectation | LocatorAssertion | BrowserAssertion | AndroidAssertion {
3050
+ if (actual && typeof actual === "object" && ANDROID_ASSERT in actual) return buildAndroidAssertion(actual as AndroidElement, message);
3040
3051
  if (isLocator(actual)) return buildLocatorAssertion(actual, message);
3041
3052
  if (isBrowserSession(actual)) return buildBrowserAssertion(actual, message);
3042
3053
  return expectValue(actual as Provenanced, message);
3043
3054
  }
3044
3055
 
3056
+ /** Retrying native Android assertions. Timeout is in milliseconds (default 10 s;
3057
+ * zero performs one observation). Each assertion records one Android step. */
3058
+ export interface AndroidMatchers {
3059
+ toBeVisible(options?: { timeout?: number }): Promise<void>;
3060
+ toBeHidden(options?: { timeout?: number }): Promise<void>;
3061
+ toHaveText(expected: string | RegExp, options?: { timeout?: number }): Promise<void>;
3062
+ toContainText(expected: string | RegExp, options?: { timeout?: number }): Promise<void>;
3063
+ }
3064
+ export interface AndroidAssertion extends AndroidMatchers { not: AndroidMatchers }
3065
+ function buildAndroidAssertion(element: AndroidElement, message?: string): AndroidAssertion {
3066
+ const matchers = (negated: boolean): AndroidMatchers => {
3067
+ const run = async (matcher: AndroidMatcher, expected?: string | RegExp, timeout?: number) => {
3068
+ const result = await element[ANDROID_ASSERT](matcher, negated, expected, timeout);
3069
+ const error = result.error === undefined ? undefined : new ExpectationError(String(result.error));
3070
+ if (error) error.cause = result.error;
3071
+ recordAssertion({ matcher, negated, passed: !error, message, sourceSeq: result.sourceSeq,
3072
+ actual: safeSerialize(result.actual), expected: expected === undefined ? undefined : safeSerialize(assertionExpected(expected)), error: error?.message });
3073
+ if (error) throw error;
3074
+ };
3075
+ return {
3076
+ toBeVisible: options => run("toBeVisible", undefined, options?.timeout),
3077
+ toBeHidden: options => run("toBeHidden", undefined, options?.timeout),
3078
+ toHaveText: (expected, options) => run("toHaveText", expected, options?.timeout),
3079
+ toContainText: (expected, options) => run("toContainText", expected, options?.timeout),
3080
+ };
3081
+ };
3082
+ return Object.assign(matchers(false), { not: matchers(true) });
3083
+ }
3084
+
3045
3085
  function expectValue(actual: Provenanced, message?: string): Expectation {
3046
3086
  // The first parameter is typed to the {@link Provenanced} family so a raw
3047
3087
  // value (`expect(res.status === 200)`, `expect(2 + 2)`) is a *compile error* —