Skip to content

Commit

Permalink
Resolves #263 (#264)
Browse files Browse the repository at this point in the history
* query options are not always camelCased

* removed default values from mutually exclusive query options

* add e2e tests
  • Loading branch information
waggledans authored Aug 21, 2024
1 parent 56025e9 commit d916ab1
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 9 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ This package if installed globally can be used as CLI tool to access the API fro
```sh
$ npm install -g saucelabs
...
$ sl listJobs $SAUCE_USERNAME --limit 5 --region eu
$ sl listJobs $SAUCE_USERNAME 5 --region eu
{ jobs:
[ { id: '19dab74f8fd848518f8d2c2cee3a6fbd' },
{ id: 'dc08ca0c7fa14eee909a093d11567328' },
Expand Down Expand Up @@ -104,7 +104,7 @@ or start Sauce Connect Proxy in EU datacenter:
# start Sauce Connect tunnel for eu-central-1 region
$ sl sc --region eu --tunnel-name "my-tunnel"
# run a specific Sauce Connect version
$ sl sc --scVersion 4.5.4
$ sl sc --scVersion 4.9.1
# see all available Sauce Connect parameters via:
$ sl sc --help
```
Expand Down
5 changes: 3 additions & 2 deletions apis/sauce.json
Original file line number Diff line number Diff line change
Expand Up @@ -1087,15 +1087,16 @@
"$ref": "#/parameters/full"
},
{
"default": false,
"required": false,
"description": "Only return manual jobs",
"in": "query",
"name": "manual_only",
"type": "boolean"
},
{
"default": false,
"required": false,
"in": "query",
"description": "Only return automated jobs",
"name": "auto_only",
"type": "boolean"
},
Expand Down
2 changes: 1 addition & 1 deletion docs/interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The following commands are available via package or cli tool:
<h3>Example:</h3>
<code>api.listJobs(username, { ...options })</code>
<br><h4>Options</h4>
<ul> <li><b>limit</b>: Number of results to return</li> <li><b>subaccounts</b>: Include subaccounts in list of jobs</li> <li><b>full</b>: Should the response result contain everything or just the basics</li> <li><b>manual_only</b>: Only return manual jobs</li> <li><b>auto_only</b>: No description available.</li> <li><b>name</b>: name of the job</li> <li><b>owner_type</b>: owner type for jobs</li> <li><b>owner</b>: username of owner of the jobs</li> <li><b>from</b>: receive jobs beginning of a specific timestamp</li> <li><b>to</b>: receive jobs until specific timestamp</li> </ul> </td>
<ul> <li><b>limit</b>: Number of results to return</li> <li><b>subaccounts</b>: Include subaccounts in list of jobs</li> <li><b>full</b>: Should the response result contain everything or just the basics</li> <li><b>manual_only</b>: Only return manual jobs</li> <li><b>auto_only</b>: Only return automated jobs</li> <li><b>name</b>: name of the job</li> <li><b>owner_type</b>: owner type for jobs</li> <li><b>owner</b>: username of owner of the jobs</li> <li><b>from</b>: receive jobs beginning of a specific timestamp</li> <li><b>to</b>: receive jobs until specific timestamp</li> </ul> </td>
</tr>
<tr>
<td>
Expand Down
51 changes: 51 additions & 0 deletions e2e/jobs.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import SauceLabs from '../build';
// import SauceLabs from 'saucelabs';

// Only run the test when the env var is present
// in GitHub Actions, otherwise it fails for untrusted PRs
const SKIP_TEST = process.env.GITHUB_RUN_ID && !process.env.SAUCE_USERNAME;

jest.setTimeout(60 * 1000); // 60s should be sufficient to boot SC

/**
* unmock
*/
jest.unmock('https').unmock('got').unmock('yargs');

test('should receive 400', async () => {
if (SKIP_TEST) {
return;
}
const api = new SauceLabs();
await expect(
api.listJobs(process.env.SAUCE_USERNAME, {
limit: 1,
autoOnly: true,
manualOnly: true,
})
).rejects.toThrow(
'Failed calling listJobs: Response code 400 (Bad Request), {"message":"Invalid combination of arguments."}'
);
});

test('should be able to list automated jobs', async () => {
if (SKIP_TEST) {
return;
}
const api = new SauceLabs();
await api.listJobs(process.env.SAUCE_USERNAME, {
limit: 1,
autoOnly: true,
});
});

test('should be able to list live-testing jobs', async () => {
if (SKIP_TEST) {
return;
}
const api = new SauceLabs();
await api.listJobs(process.env.SAUCE_USERNAME, {
limit: 1,
manualOnly: true,
});
});
14 changes: 14 additions & 0 deletions e2e/sc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ jest
.unmock('compressing')
.unmock('zlib');

test('should be able to get Sauce Connect versions', async () => {
if (SKIP_TEST) {
return;
}
const api = new SauceLabs();
const scVersion = await api.scVersions({
clientVersion: '5.1.0',
clientHost: 'darwin-arm64',
});
expect(scVersion.status).toEqual('UPGRADE');
expect(scVersion.latest_version).toMatch(/5\./);
console.log(scVersion.download_url);
});

test('should not be able to run Sauce Connect due to invalid credentials', async () => {
if (SKIP_TEST) {
return;
Expand Down
13 changes: 10 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,9 +529,16 @@ export default class SauceLabs {
const options = args.slice(pathParams.length)[0] || {};
for (const optionParam of params.filter((p) => p.in === 'query')) {
const expectedType = optionParam.type.replace('integer', 'number');
// I'm not sure why query param name is camel-cased here, underscore params do exist in Sauce Labs.
// support query options passed in camelCased form.
const optionName = camelCase(optionParam.name);
const optionValue = options[optionName] || options[optionParam.name];
let optionValueFromParams = options[optionName];
if (
optionParam.name !== optionName &&
typeof optionValueFromParams === 'undefined'
) {
optionValueFromParams = options[optionParam.name];
}
const optionValue = optionValueFromParams;
const isRequired =
Boolean(optionParam.required) ||
(typeof optionParam.required === 'undefined' &&
Expand Down Expand Up @@ -583,7 +590,7 @@ export default class SauceLabs {
} catch (err) {
throw new Error(
`Failed calling ${propName}: ${err.message}, ${
err.response && err.response.body
err.response && JSON.stringify(err.response.body)
}`
);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ test('should output failure msg for createJob API', async () => {
const error = await api.createJob({framework: ''}).catch((err) => err);

expect(error.message).toBe(
'Failed calling createJob: Response code 422 (Unprocessable Entity), empty framework'
'Failed calling createJob: Response code 422 (Unprocessable Entity), "empty framework"'
);
});

Expand Down

0 comments on commit d916ab1

Please sign in to comment.