@mobilewright/driver-mobilenext 0.0.1 → 0.0.41

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mobilewright/driver-mobilenext",
3
- "version": "0.0.1",
3
+ "version": "0.0.41",
4
4
  "description": "MobileNext driver for Mobilewright",
5
5
  "homepage": "https://mobilewright.dev",
6
6
  "license": "Apache-2.0",
@@ -29,7 +29,7 @@
29
29
  "dist"
30
30
  ],
31
31
  "dependencies": {
32
- "@mobilewright/protocol": "^0.0.1",
32
+ "@mobilewright/protocol": "^0.0.41",
33
33
  "debug": "^4.4.3",
34
34
  "ws": "^8.18.0"
35
35
  },
package/dist/example.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=example.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"example.d.ts","sourceRoot":"","sources":["../src/example.ts"],"names":[],"mappings":""}
package/dist/example.js DELETED
@@ -1,39 +0,0 @@
1
- import { writeFileSync } from 'node:fs';
2
- import { MobileUseDriver } from './driver.js';
3
- const API_KEY = "mob_Z2WFuDmQR3v7A5HJN1bJ18UjETPr4cDueZEt";
4
- async function main() {
5
- const driver = new MobileUseDriver({
6
- // region: 'us-west-2',
7
- // apiKey: 'your-api-key',
8
- apiKey: API_KEY,
9
- });
10
- // Connect to a device
11
- const session = await driver.connect({
12
- platform: 'ios',
13
- });
14
- console.log('Connected:', session);
15
- // Get screen size
16
- const screenSize = await driver.getScreenSize();
17
- console.log('Screen size:', screenSize);
18
- // Get orientation
19
- const orientation = await driver.getOrientation();
20
- console.log('Orientation:', orientation);
21
- // Take a screenshot and save to file
22
- const screenshot = await driver.screenshot();
23
- writeFileSync('screenshot.png', screenshot);
24
- console.log('Screenshot saved to screenshot.png (%d bytes)', screenshot.length);
25
- // List elements on screen
26
- const elements = await driver.getViewHierarchy();
27
- console.log('Elements on screen:', JSON.stringify(elements, null, 2));
28
- // Type text
29
- await driver.typeText('Hello from mobile-use driver!');
30
- console.log('Typed text on screen');
31
- // Disconnect
32
- await driver.disconnect();
33
- console.log('Disconnected');
34
- }
35
- main().catch((err) => {
36
- console.error(err);
37
- process.exit(1);
38
- });
39
- //# sourceMappingURL=example.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"example.js","sourceRoot":"","sources":["../src/example.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,OAAO,GAAG,0CAA0C,CAAC;AAE3D,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,uBAAuB;QACvB,0BAA0B;QAC1B,MAAM,EAAE,OAAO;KAChB,CAAC,CAAC;IAEH,sBAAsB;IACtB,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;QACnC,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEnC,kBAAkB;IAClB,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;IAExC,kBAAkB;IAClB,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,cAAc,EAAE,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAEzC,qCAAqC;IACrC,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7C,aAAa,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,+CAA+C,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;IAEhF,0BAA0B;IAC1B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,gBAAgB,EAAE,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtE,YAAY;IACZ,MAAM,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IAEpC,aAAa;IACb,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAC1B,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAC9B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1,10 +0,0 @@
1
- export interface GitInfo {
2
- repoUrl?: string;
3
- branch?: string;
4
- commitSha?: string;
5
- authorName?: string;
6
- commitMessage?: string;
7
- }
8
- export declare function normalizeRepoUrl(url: string): string;
9
- export declare function getGitInfo(): GitInfo;
10
- //# sourceMappingURL=git-info.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-info.d.ts","sourceRoot":"","sources":["../src/git-info.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAcD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUpD;AAoHD,wBAAgB,UAAU,IAAI,OAAO,CAUpC"}
package/dist/git-info.js DELETED
@@ -1,142 +0,0 @@
1
- import { execSync } from 'node:child_process';
2
- function runGit(args) {
3
- try {
4
- const result = execSync(['git', ...args].join(' '), {
5
- encoding: 'utf8',
6
- stdio: ['ignore', 'pipe', 'ignore'],
7
- }).trim();
8
- return result || undefined;
9
- }
10
- catch {
11
- return undefined;
12
- }
13
- }
14
- export function normalizeRepoUrl(url) {
15
- const sshMatch = url.match(/^git@([^:]+):(.+?)(?:\.git)?$/);
16
- if (sshMatch) {
17
- return `https://${sshMatch[1]}/${sshMatch[2]}`;
18
- }
19
- const sshProtocolMatch = url.match(/^ssh:\/\/(?:[^@]+@)?([^/]+)\/(.+?)(?:\.git)?$/);
20
- if (sshProtocolMatch) {
21
- return `https://${sshProtocolMatch[1]}/${sshProtocolMatch[2]}`;
22
- }
23
- return url.replace(/\.git$/, '');
24
- }
25
- function getGitHubInfo() {
26
- if (!process.env['GITHUB_ACTIONS']) {
27
- return undefined;
28
- }
29
- const repo = process.env['GITHUB_REPOSITORY'];
30
- return {
31
- repoUrl: repo ? `https://github.com/${repo}` : undefined,
32
- branch: process.env['GITHUB_REF_NAME'],
33
- commitSha: process.env['GITHUB_SHA'],
34
- authorName: process.env['GITHUB_ACTOR'],
35
- commitMessage: process.env['GITHUB_COMMIT_MESSAGE'] ?? runGit(['log', '-1', '--format=%s']),
36
- };
37
- }
38
- function getGitLabInfo() {
39
- if (!process.env['GITLAB_CI']) {
40
- return undefined;
41
- }
42
- return {
43
- repoUrl: process.env['CI_PROJECT_URL'],
44
- branch: process.env['CI_COMMIT_REF_NAME'],
45
- commitSha: process.env['CI_COMMIT_SHA'],
46
- authorName: process.env['GITLAB_USER_NAME'] ?? process.env['CI_COMMIT_AUTHOR'],
47
- commitMessage: process.env['CI_COMMIT_MESSAGE'],
48
- };
49
- }
50
- function getJenkinsInfo() {
51
- if (!process.env['JENKINS_URL']) {
52
- return undefined;
53
- }
54
- const rawUrl = process.env['GIT_URL'];
55
- const branch = process.env['GIT_BRANCH'] ?? process.env['BRANCH_NAME'] ?? process.env['GIT_LOCAL_BRANCH'];
56
- return {
57
- repoUrl: rawUrl ? normalizeRepoUrl(rawUrl) : undefined,
58
- branch,
59
- commitSha: process.env['GIT_COMMIT'],
60
- authorName: process.env['GIT_AUTHOR_NAME'],
61
- commitMessage: runGit(['log', '-1', '--format=%s']),
62
- };
63
- }
64
- function getCircleCIInfo() {
65
- if (!process.env['CIRCLECI']) {
66
- return undefined;
67
- }
68
- const username = process.env['CIRCLE_PROJECT_USERNAME'];
69
- const reponame = process.env['CIRCLE_PROJECT_REPONAME'];
70
- const vcsType = process.env['CIRCLE_VCS_TYPE'] ?? 'github';
71
- const host = vcsType === 'bitbucket' ? 'bitbucket.org' : 'github.com';
72
- return {
73
- repoUrl: username && reponame ? `https://${host}/${username}/${reponame}` : undefined,
74
- branch: process.env['CIRCLE_BRANCH'],
75
- commitSha: process.env['CIRCLE_SHA1'],
76
- authorName: process.env['CIRCLE_USERNAME'],
77
- commitMessage: runGit(['log', '-1', '--format=%s']),
78
- };
79
- }
80
- function getTravisInfo() {
81
- if (!process.env['TRAVIS']) {
82
- return undefined;
83
- }
84
- const slug = process.env['TRAVIS_REPO_SLUG'];
85
- return {
86
- repoUrl: slug ? `https://github.com/${slug}` : undefined,
87
- branch: process.env['TRAVIS_PULL_REQUEST_BRANCH'] ?? process.env['TRAVIS_BRANCH'],
88
- commitSha: process.env['TRAVIS_COMMIT'],
89
- commitMessage: process.env['TRAVIS_COMMIT_MESSAGE'],
90
- };
91
- }
92
- function getAzureDevOpsInfo() {
93
- if (!process.env['TF_BUILD']) {
94
- return undefined;
95
- }
96
- const rawBranch = process.env['SYSTEM_PULLREQUEST_SOURCEBRANCH'] ?? process.env['BUILD_SOURCEBRANCH'];
97
- return {
98
- repoUrl: process.env['BUILD_REPOSITORY_URI'],
99
- branch: rawBranch?.replace('refs/heads/', ''),
100
- commitSha: process.env['BUILD_SOURCEVERSION'],
101
- authorName: process.env['BUILD_REQUESTEDFOR'],
102
- commitMessage: process.env['BUILD_SOURCEVERSIONMESSAGE'],
103
- };
104
- }
105
- function getBitbucketInfo() {
106
- if (!process.env['BITBUCKET_PIPELINE_UUID']) {
107
- return undefined;
108
- }
109
- const slug = process.env['BITBUCKET_REPO_FULL_NAME'];
110
- return {
111
- repoUrl: slug ? `https://bitbucket.org/${slug}` : undefined,
112
- branch: process.env['BITBUCKET_BRANCH'],
113
- commitSha: process.env['BITBUCKET_COMMIT'],
114
- commitMessage: runGit(['log', '-1', '--format=%s']),
115
- };
116
- }
117
- function getLocalGitInfo() {
118
- const gitDir = runGit(['rev-parse', '--git-dir']);
119
- if (!gitDir) {
120
- return undefined;
121
- }
122
- const rawUrl = runGit(['config', '--get', 'remote.origin.url']);
123
- return {
124
- repoUrl: rawUrl ? normalizeRepoUrl(rawUrl) : undefined,
125
- branch: runGit(['rev-parse', '--abbrev-ref', 'HEAD']),
126
- commitSha: runGit(['rev-parse', 'HEAD']),
127
- authorName: runGit(['log', '-1', '--format=%an']),
128
- commitMessage: runGit(['log', '-1', '--format=%s']),
129
- };
130
- }
131
- export function getGitInfo() {
132
- const info = getGitHubInfo()
133
- ?? getGitLabInfo()
134
- ?? getJenkinsInfo()
135
- ?? getCircleCIInfo()
136
- ?? getTravisInfo()
137
- ?? getAzureDevOpsInfo()
138
- ?? getBitbucketInfo()
139
- ?? getLocalGitInfo();
140
- return info ?? {};
141
- }
142
- //# sourceMappingURL=git-info.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-info.js","sourceRoot":"","sources":["../src/git-info.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=git-info.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-info.test.d.ts","sourceRoot":"","sources":["../src/git-info.test.ts"],"names":[],"mappings":""}
@@ -1,107 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- import { getGitInfo, normalizeRepoUrl } from './git-info.js';
3
- const ALL_CI_KEYS = [
4
- 'GITHUB_ACTIONS', 'GITLAB_CI', 'JENKINS_URL',
5
- 'CIRCLECI', 'TRAVIS', 'TF_BUILD', 'BITBUCKET_PIPELINE_UUID',
6
- ];
7
- function withCIEnv(vars, fn) {
8
- const saved = {};
9
- const keysToManage = [...new Set([...ALL_CI_KEYS, ...Object.keys(vars)])];
10
- for (const key of keysToManage) {
11
- saved[key] = process.env[key];
12
- delete process.env[key];
13
- }
14
- for (const [key, value] of Object.entries(vars)) {
15
- process.env[key] = value;
16
- }
17
- try {
18
- fn();
19
- }
20
- finally {
21
- for (const key of keysToManage) {
22
- if (saved[key] === undefined) {
23
- delete process.env[key];
24
- }
25
- else {
26
- process.env[key] = saved[key];
27
- }
28
- }
29
- }
30
- }
31
- test('normalizeRepoUrl converts SSH git@ URL to HTTPS', () => {
32
- expect(normalizeRepoUrl('git@github.com:org/repo.git')).toBe('https://github.com/org/repo');
33
- });
34
- test('normalizeRepoUrl converts ssh:// URL to HTTPS', () => {
35
- expect(normalizeRepoUrl('ssh://git@github.com/org/repo.git')).toBe('https://github.com/org/repo');
36
- });
37
- test('normalizeRepoUrl strips .git suffix from HTTPS URL', () => {
38
- expect(normalizeRepoUrl('https://github.com/org/repo.git')).toBe('https://github.com/org/repo');
39
- });
40
- test('normalizeRepoUrl leaves plain HTTPS URL unchanged', () => {
41
- expect(normalizeRepoUrl('https://github.com/org/repo')).toBe('https://github.com/org/repo');
42
- });
43
- test('getGitInfo reads GitHub Actions environment variables', () => {
44
- withCIEnv({
45
- GITHUB_ACTIONS: 'true',
46
- GITHUB_REPOSITORY: 'myorg/myrepo',
47
- GITHUB_SHA: 'abc123def456',
48
- GITHUB_REF_NAME: 'main',
49
- GITHUB_ACTOR: 'octocat',
50
- GITHUB_COMMIT_MESSAGE: 'feat: add feature',
51
- }, () => {
52
- const info = getGitInfo();
53
- expect(info.repoUrl).toBe('https://github.com/myorg/myrepo');
54
- expect(info.commitSha).toBe('abc123def456');
55
- expect(info.branch).toBe('main');
56
- expect(info.authorName).toBe('octocat');
57
- expect(info.commitMessage).toBe('feat: add feature');
58
- });
59
- });
60
- test('getGitInfo reads GitLab CI environment variables', () => {
61
- withCIEnv({
62
- GITLAB_CI: 'true',
63
- CI_PROJECT_URL: 'https://gitlab.com/myorg/myrepo',
64
- CI_COMMIT_SHA: 'deadbeef',
65
- CI_COMMIT_REF_NAME: 'feature-branch',
66
- GITLAB_USER_NAME: 'alice',
67
- CI_COMMIT_MESSAGE: 'fix: bug',
68
- }, () => {
69
- const info = getGitInfo();
70
- expect(info.repoUrl).toBe('https://gitlab.com/myorg/myrepo');
71
- expect(info.commitSha).toBe('deadbeef');
72
- expect(info.branch).toBe('feature-branch');
73
- expect(info.authorName).toBe('alice');
74
- expect(info.commitMessage).toBe('fix: bug');
75
- });
76
- });
77
- test('getGitInfo reads Azure DevOps environment variables and strips refs/heads/ prefix', () => {
78
- withCIEnv({
79
- TF_BUILD: 'true',
80
- BUILD_REPOSITORY_URI: 'https://dev.azure.com/org/project/_git/repo',
81
- BUILD_SOURCEBRANCH: 'refs/heads/main',
82
- BUILD_SOURCEVERSION: 'abc123',
83
- BUILD_REQUESTEDFOR: 'Bob',
84
- BUILD_SOURCEVERSIONMESSAGE: 'chore: update deps',
85
- }, () => {
86
- const info = getGitInfo();
87
- expect(info.branch).toBe('main');
88
- expect(info.repoUrl).toBe('https://dev.azure.com/org/project/_git/repo');
89
- expect(info.authorName).toBe('Bob');
90
- });
91
- });
92
- test('getGitInfo falls back to local git when no CI env vars are set', () => {
93
- // This test runs inside the mobilewright git repo, so local git should work.
94
- withCIEnv({}, () => {
95
- const info = getGitInfo();
96
- expect(typeof info.branch).toBe('string');
97
- expect(typeof info.commitSha).toBe('string');
98
- expect(info.commitSha).toHaveLength(40);
99
- });
100
- });
101
- test('getGitInfo returns empty object when not in a git repo and no CI env vars', () => {
102
- // Simulate a non-git environment by checking we get an object (may be empty)
103
- const info = getGitInfo();
104
- expect(typeof info).toBe('object');
105
- expect(info).not.toBeNull();
106
- });
107
- //# sourceMappingURL=git-info.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-info.test.js","sourceRoot":"","sources":["../src/git-info.test.ts"],"names":[],"mappings":"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"}
@@ -1,13 +0,0 @@
1
- export interface UploadTestResultParams {
2
- apiKey: string;
3
- jsonResultsPath: string;
4
- outputDir: string;
5
- name?: string;
6
- tags?: string[];
7
- environment?: string;
8
- _fetchFn?: typeof fetch;
9
- }
10
- export declare function uploadTestResult(params: UploadTestResultParams): Promise<{
11
- url: string;
12
- }>;
13
- //# sourceMappingURL=upload-client.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-client.d.ts","sourceRoot":"","sources":["../src/upload-client.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,KAAK,CAAC;CACzB;AA6ED,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CA4D/F"}
@@ -1,110 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
- import { createRequire } from 'node:module';
3
- import { randomUUID } from 'node:crypto';
4
- import createDebug from 'debug';
5
- import { getGitInfo } from './git-info.js';
6
- const _require = createRequire(import.meta.url);
7
- const debug = createDebug('mw:reporter:upload');
8
- const BASE_URL = 'https://api.mobilenext.ai';
9
- const DASHBOARD_BASE_URL = 'https://app.mobilenext.ai';
10
- function extensionForContentType(contentType) {
11
- const extensions = {
12
- 'image/png': 'png',
13
- 'image/jpeg': 'jpg',
14
- 'image/webp': 'webp',
15
- 'image/gif': 'gif',
16
- };
17
- return extensions[contentType] ?? 'bin';
18
- }
19
- async function uploadAttachmentBodies(obj, testResultId, apiKey, fetchFn) {
20
- if (!obj || typeof obj !== 'object') {
21
- return;
22
- }
23
- if (Array.isArray(obj)) {
24
- for (const item of obj) {
25
- await uploadAttachmentBodies(item, testResultId, apiKey, fetchFn);
26
- }
27
- return;
28
- }
29
- const record = obj;
30
- if (Array.isArray(record['attachments'])) {
31
- for (const att of record['attachments']) {
32
- if (typeof att['body'] === 'string') {
33
- const contentType = typeof att['contentType'] === 'string' ? att['contentType'] : 'application/octet-stream';
34
- const ext = extensionForContentType(contentType);
35
- const assetName = `${randomUUID()}.${ext}`;
36
- const buffer = Buffer.from(att['body'], 'base64');
37
- const sizeKB = (buffer.length / 1024).toFixed(1);
38
- debug('uploading attachment name=%s contentType=%s size=%skB as %s', att['name'], contentType, sizeKB, assetName);
39
- const form = new FormData();
40
- form.append('name', assetName);
41
- form.append('file', new Blob([buffer], { type: contentType }), assetName);
42
- const res = await fetchFn(`${BASE_URL}/api/v1/test-results/${testResultId}/assets`, {
43
- method: 'POST',
44
- headers: { 'Authorization': `Bearer ${apiKey}` },
45
- body: form,
46
- });
47
- if (!res.ok) {
48
- throw new Error(`Failed to upload attachment "${att['name']}": ${res.status}`);
49
- }
50
- const asset = await res.json();
51
- delete att['body'];
52
- att['assetId'] = asset.id;
53
- debug('attachment uploaded assetId=%s', asset.id);
54
- }
55
- }
56
- }
57
- for (const value of Object.values(record)) {
58
- await uploadAttachmentBodies(value, testResultId, apiKey, fetchFn);
59
- }
60
- }
61
- export async function uploadTestResult(params) {
62
- const fetchFn = params._fetchFn ?? fetch;
63
- const pkg = _require('../package.json');
64
- const userAgent = `mobilewright/${pkg.version}`;
65
- const gitInfo = getGitInfo();
66
- const hasGitInfo = Object.values(gitInfo).some(v => v !== undefined);
67
- debug('creating test result name=%s userAgent=%s', params.name ?? 'Test Run', userAgent);
68
- const createRes = await fetchFn(`${BASE_URL}/api/v1/test-results`, {
69
- method: 'POST',
70
- headers: {
71
- 'Authorization': `Bearer ${params.apiKey}`,
72
- 'Content-Type': 'application/json',
73
- },
74
- body: JSON.stringify({
75
- name: params.name ?? 'Test Run',
76
- userAgent,
77
- ...(hasGitInfo ? { git: gitInfo } : {}),
78
- }),
79
- });
80
- if (!createRes.ok) {
81
- throw new Error(`Failed to create test result: ${createRes.status}`);
82
- }
83
- const testResult = await createRes.json();
84
- debug('test result created id=%s', testResult.id);
85
- // Parse into a fresh in-memory copy — original file on disk is never modified
86
- const rawJson = readFileSync(params.jsonResultsPath);
87
- const report = JSON.parse(rawJson.toString());
88
- await uploadAttachmentBodies(report, testResult.id, params.apiKey, fetchFn);
89
- const modifiedJson = JSON.stringify(report);
90
- const modifiedBuffer = Buffer.from(modifiedJson);
91
- const fileSizeKB = (modifiedBuffer.length / 1024).toFixed(1);
92
- debug('uploading report.json size=%skB path=%s', fileSizeKB, params.jsonResultsPath);
93
- const form = new FormData();
94
- form.append('name', 'report.json');
95
- form.append('file', new Blob([modifiedBuffer], { type: 'application/json' }), 'report.json');
96
- const progressTimer = setInterval(() => {
97
- debug('still uploading report.json...');
98
- }, 10_000);
99
- const uploadRes = await fetchFn(`${BASE_URL}/api/v1/test-results/${testResult.id}/assets`, {
100
- method: 'POST',
101
- headers: { 'Authorization': `Bearer ${params.apiKey}` },
102
- body: form,
103
- }).finally(() => clearInterval(progressTimer));
104
- if (!uploadRes.ok) {
105
- throw new Error(`Failed to upload report.json: ${uploadRes.status}`);
106
- }
107
- debug('upload complete url=%s', `${DASHBOARD_BASE_URL}/dashboard/test-results/${testResult.id}`);
108
- return { url: `${DASHBOARD_BASE_URL}/dashboard/test-results/${testResult.id}` };
109
- }
110
- //# sourceMappingURL=upload-client.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-client.js","sourceRoot":"","sources":["../src/upload-client.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=upload-client.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-client.test.d.ts","sourceRoot":"","sources":["../src/upload-client.test.ts"],"names":[],"mappings":""}
@@ -1,233 +0,0 @@
1
- import { test, expect } from '@playwright/test';
2
- import { writeFileSync, mkdtempSync, rmSync } from 'node:fs';
3
- import { join } from 'node:path';
4
- import { tmpdir } from 'node:os';
5
- import { uploadTestResult } from './upload-client.js';
6
- function makeMockFetch(testResultId) {
7
- const calls = [];
8
- const mockFetch = async (url, init) => {
9
- const urlStr = String(url);
10
- const headers = (init?.headers ?? {});
11
- calls.push({ url: urlStr, method: init?.method ?? 'GET', headers, body: init?.body });
12
- if (urlStr.endsWith('/test-results')) {
13
- return new Response(JSON.stringify({ id: testResultId, name: 'Test Run', userAgent: 'mobilewright/0.0.1', createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
14
- }
15
- return new Response(JSON.stringify({ id: 'asset-1', name: 'report.json', contentType: 'application/json', size: 12, createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
16
- };
17
- return { mockFetch: mockFetch, calls };
18
- }
19
- test('sends POST to test-results endpoint with apiKey, name, and userAgent', async () => {
20
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
21
- const jsonPath = join(workDir, 'results.json');
22
- writeFileSync(jsonPath, '{"tests":[]}');
23
- const { mockFetch, calls } = makeMockFetch('result-abc');
24
- await uploadTestResult({
25
- apiKey: 'mob_test_key',
26
- jsonResultsPath: jsonPath,
27
- outputDir: join(workDir, 'artifacts'),
28
- _fetchFn: mockFetch,
29
- });
30
- const createCall = calls.find(c => c.url === 'https://api.mobilenext.ai/api/v1/test-results');
31
- expect(createCall?.method).toBe('POST');
32
- const body = JSON.parse(createCall?.body);
33
- expect(body.name).toBe('Test Run');
34
- expect(body.userAgent).toMatch(/^mobilewright\//);
35
- expect(createCall?.headers['Authorization']).toBe('Bearer mob_test_key');
36
- expect(createCall?.headers['Content-Type']).toBe('application/json');
37
- rmSync(workDir, { recursive: true });
38
- });
39
- test('uses provided name in the create test result request', async () => {
40
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
41
- const jsonPath = join(workDir, 'results.json');
42
- writeFileSync(jsonPath, '{}');
43
- const { mockFetch, calls } = makeMockFetch('result-abc');
44
- await uploadTestResult({
45
- apiKey: 'mob_key',
46
- jsonResultsPath: jsonPath,
47
- outputDir: join(workDir, 'artifacts'),
48
- name: 'Nightly Suite',
49
- _fetchFn: mockFetch,
50
- });
51
- const createCall = calls.find(c => c.url === 'https://api.mobilenext.ai/api/v1/test-results');
52
- const body = JSON.parse(createCall?.body);
53
- expect(body.name).toBe('Nightly Suite');
54
- rmSync(workDir, { recursive: true });
55
- });
56
- test('uploads report.json as multipart FormData to the asset endpoint', async () => {
57
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
58
- const jsonPath = join(workDir, 'results.json');
59
- writeFileSync(jsonPath, '{"tests":[]}');
60
- const { mockFetch, calls } = makeMockFetch('result-abc');
61
- await uploadTestResult({
62
- apiKey: 'mob_test_key',
63
- jsonResultsPath: jsonPath,
64
- outputDir: join(workDir, 'artifacts'),
65
- _fetchFn: mockFetch,
66
- });
67
- const assetCall = calls.find(c => c.url.includes('/assets'));
68
- expect(assetCall?.url).toBe('https://api.mobilenext.ai/api/v1/test-results/result-abc/assets');
69
- expect(assetCall?.method).toBe('POST');
70
- expect(assetCall?.body).toBeInstanceOf(FormData);
71
- expect(assetCall?.headers['Authorization']).toBe('Bearer mob_test_key');
72
- rmSync(workDir, { recursive: true });
73
- });
74
- test('returns the dashboard URL for the created test result', async () => {
75
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
76
- const jsonPath = join(workDir, 'results.json');
77
- writeFileSync(jsonPath, '{}');
78
- const { mockFetch } = makeMockFetch('my-test-id-123');
79
- const result = await uploadTestResult({
80
- apiKey: 'mob_key',
81
- jsonResultsPath: jsonPath,
82
- outputDir: join(workDir, 'artifacts'),
83
- _fetchFn: mockFetch,
84
- });
85
- expect(result.url).toBe('https://app.mobilenext.ai/dashboard/test-results/my-test-id-123');
86
- rmSync(workDir, { recursive: true });
87
- });
88
- test('throws when create test result API returns a non-2xx status', async () => {
89
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
90
- const jsonPath = join(workDir, 'results.json');
91
- writeFileSync(jsonPath, '{}');
92
- const failingFetch = async (_url, _init) => new Response(JSON.stringify({ error: 'Unauthorized' }), { status: 401 });
93
- await expect(uploadTestResult({
94
- apiKey: 'bad-key',
95
- jsonResultsPath: jsonPath,
96
- outputDir: join(workDir, 'artifacts'),
97
- _fetchFn: failingFetch,
98
- })).rejects.toThrow('401');
99
- rmSync(workDir, { recursive: true });
100
- });
101
- test('throws when asset upload API returns a non-2xx status', async () => {
102
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
103
- const jsonPath = join(workDir, 'results.json');
104
- writeFileSync(jsonPath, '{}');
105
- const mockFetch = async (url, _init) => {
106
- if (String(url).endsWith('/test-results')) {
107
- return new Response(JSON.stringify({ id: 'result-abc', name: 'Test Run', userAgent: 'mobilewright/0.0.1', createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
108
- }
109
- return new Response(JSON.stringify({ error: 'Server Error' }), { status: 500 });
110
- };
111
- await expect(uploadTestResult({
112
- apiKey: 'mob_key',
113
- jsonResultsPath: jsonPath,
114
- outputDir: join(workDir, 'artifacts'),
115
- _fetchFn: mockFetch,
116
- })).rejects.toThrow('500');
117
- rmSync(workDir, { recursive: true });
118
- });
119
- test('uploads inline attachment bodies as separate assets before report.json', async () => {
120
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
121
- const jsonPath = join(workDir, 'results.json');
122
- const pngBase64 = Buffer.from('fake-png-data').toString('base64');
123
- const report = {
124
- suites: [{ specs: [{ tests: [{ results: [{ attachments: [
125
- { name: 'screenshot', contentType: 'image/png', body: pngBase64 },
126
- ] }] }] }] }],
127
- };
128
- writeFileSync(jsonPath, JSON.stringify(report));
129
- let assetCallCount = 0;
130
- const mockFetch = async (url, init) => {
131
- const urlStr = String(url);
132
- if (urlStr.endsWith('/test-results')) {
133
- return new Response(JSON.stringify({ id: 'result-abc', name: 'Test Run', userAgent: 'mobilewright/0.0.1', createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
134
- }
135
- assetCallCount++;
136
- return new Response(JSON.stringify({ id: `asset-${assetCallCount}`, name: 'x', contentType: 'image/png', size: 10, createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
137
- };
138
- await uploadTestResult({
139
- apiKey: 'mob_key',
140
- jsonResultsPath: jsonPath,
141
- outputDir: join(workDir, 'artifacts'),
142
- _fetchFn: mockFetch,
143
- });
144
- // 2 asset calls: one for the PNG attachment, one for report.json
145
- expect(assetCallCount).toBe(2);
146
- rmSync(workDir, { recursive: true });
147
- });
148
- test('removes body and sets assetId in the uploaded report.json', async () => {
149
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
150
- const jsonPath = join(workDir, 'results.json');
151
- const pngBase64 = Buffer.from('fake-png-data').toString('base64');
152
- const report = {
153
- suites: [{ specs: [{ tests: [{ results: [{ attachments: [
154
- { name: 'screenshot', contentType: 'image/png', body: pngBase64 },
155
- ] }] }] }] }],
156
- };
157
- writeFileSync(jsonPath, JSON.stringify(report));
158
- let assetCallCount = 0;
159
- let capturedReportForm;
160
- const mockFetch = async (url, init) => {
161
- const urlStr = String(url);
162
- if (urlStr.endsWith('/test-results')) {
163
- return new Response(JSON.stringify({ id: 'result-abc', name: 'Test Run', userAgent: 'mobilewright/0.0.1', createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
164
- }
165
- assetCallCount++;
166
- if (assetCallCount === 2) {
167
- capturedReportForm = init?.body;
168
- }
169
- return new Response(JSON.stringify({ id: `asset-${assetCallCount}`, name: 'x', contentType: 'image/png', size: 10, createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
170
- };
171
- await uploadTestResult({
172
- apiKey: 'mob_key',
173
- jsonResultsPath: jsonPath,
174
- outputDir: join(workDir, 'artifacts'),
175
- _fetchFn: mockFetch,
176
- });
177
- const reportFile = capturedReportForm?.get('file');
178
- const parsedReport = JSON.parse(await reportFile.text());
179
- const att = parsedReport.suites[0].specs[0].tests[0].results[0].attachments[0];
180
- expect(att['body']).toBeUndefined();
181
- expect(att['assetId']).toBe('asset-1');
182
- rmSync(workDir, { recursive: true });
183
- });
184
- test('does not modify the original json file on disk', async () => {
185
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
186
- const jsonPath = join(workDir, 'results.json');
187
- const pngBase64 = Buffer.from('fake-png-data').toString('base64');
188
- const report = {
189
- suites: [{ specs: [{ tests: [{ results: [{ attachments: [
190
- { name: 'screenshot', contentType: 'image/png', body: pngBase64 },
191
- ] }] }] }] }],
192
- };
193
- const originalJson = JSON.stringify(report);
194
- writeFileSync(jsonPath, originalJson);
195
- const { mockFetch } = makeMockFetch('result-abc');
196
- await uploadTestResult({
197
- apiKey: 'mob_key',
198
- jsonResultsPath: jsonPath,
199
- outputDir: join(workDir, 'artifacts'),
200
- _fetchFn: mockFetch,
201
- });
202
- const { readFileSync: read } = await import('node:fs');
203
- expect(read(jsonPath, 'utf8')).toBe(originalJson);
204
- rmSync(workDir, { recursive: true });
205
- });
206
- test('leaves path-based attachments unchanged', async () => {
207
- const workDir = mkdtempSync(join(tmpdir(), 'mw-upload-test-'));
208
- const jsonPath = join(workDir, 'results.json');
209
- const report = {
210
- suites: [{ specs: [{ tests: [{ results: [{ attachments: [
211
- { name: 'video', contentType: 'video/mp4', path: '/some/path/video.mp4' },
212
- ] }] }] }] }],
213
- };
214
- writeFileSync(jsonPath, JSON.stringify(report));
215
- let assetCallCount = 0;
216
- const mockFetch = async (url, _init) => {
217
- if (String(url).endsWith('/test-results')) {
218
- return new Response(JSON.stringify({ id: 'result-abc', name: 'Test Run', userAgent: 'mobilewright/0.0.1', createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
219
- }
220
- assetCallCount++;
221
- return new Response(JSON.stringify({ id: 'asset-1', name: 'report.json', contentType: 'application/json', size: 10, createdAt: '2026-01-01T00:00:00Z' }), { status: 201 });
222
- };
223
- await uploadTestResult({
224
- apiKey: 'mob_key',
225
- jsonResultsPath: jsonPath,
226
- outputDir: join(workDir, 'artifacts'),
227
- _fetchFn: mockFetch,
228
- });
229
- // Only 1 asset call: just report.json (no upload for path-based attachments)
230
- expect(assetCallCount).toBe(1);
231
- rmSync(workDir, { recursive: true });
232
- });
233
- //# sourceMappingURL=upload-client.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"upload-client.test.js","sourceRoot":"","sources":["../src/upload-client.test.ts"],"names":[],"mappings":"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"}