Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PINDP-1808: comments for unit tests #134

Merged
merged 1 commit into from
Nov 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions nodejs/Makefile
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
# Try to keep the make targets below in sync with the other Makefiles in this repo.

# Run the unit tests
tests:
jest

# Verify that the prerequisites for the end-to-end tests are met.
e2e_setup:
@echo end to end tests set up...
../common/scripts/e2e_tests_prerequisites

# Run the end-to-end tests.
e2e_tests: e2e_setup
@echo end to end tests...
../common/scripts/e2e_tests_read
../common/scripts/e2e_tests_write
../common/scripts/e2e_tests_ads

# Run the linter to verify the code.
lint:
DEBUG=eslint:cli-engine yarn run eslint src scripts

# Run the linter to verify the code and fix any issues.
lint-fix:
yarn run eslint --fix --format summary-chart src scripts

Expand Down
15 changes: 15 additions & 0 deletions nodejs/src/access_token.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,21 @@ describe('v5 access_token tests', () => {
process.env = SAVED_ENV;
});

// test all of the ways that access tokens can be fetched

test('access token from environment', async() => {
const mock_api_config = jest.fn();
mock_api_config.app_id = 'test-app-id';
mock_api_config.app_secret = 'test-app-secret';
mock_api_config.oauth_token_dir = 'test-token-dir';

// The name of the access token is converted to upper case to find
// it in the process environment.
process.env.ACCESS_TOKEN_FROM_ENV = 'access token 42';
const access_token = new AccessToken(mock_api_config,
{ name: 'access_token_from_env' });
await access_token.fetch({});
// verify that the hash is the correct SHA256 value
// echo -n 'access token 42' | shasum -a 256
expect('553c1f363497ba07fecc989425e57e37c2b5f57ff7476c79dfd580ef0741db88')
.toEqual(access_token.hashed());
Expand All @@ -52,14 +57,17 @@ describe('v5 access_token tests', () => {
// check output
console.log = jest.fn();

// Test access token JSON file read
fs.readFileSync.mockReturnValue(access_token_json);
const access_token = new AccessToken(mock_api_config,
{ name: 'access_token_from_file' });
await access_token.fetch({});
// verify that the hash is the correct SHA256 value
// echo -n 'test access token from json' | shasum -a 256
expect('8de299eafa6932d8be18d7ff053d3bc6361c2b66ae1922f55fbf390d42de4cf6')
.toEqual(access_token.hashed());

// verify that the hash is the correct SHA256 value
// echo -n 'test refresh token from json' | shasum -a 256
expect('15569cfd5a27881329e842dfea303e05ec60c99fbdebcdaa20d2445647297072')
.toEqual(access_token.hashed_refresh_token());
Expand All @@ -71,6 +79,7 @@ describe('v5 access_token tests', () => {
callback(null, 42);
});

// Test access token JSON file write
fs.write.mockImplementation((fd, json, callback) => {
expect(42).toEqual(fd);
expect(access_token_json).toEqual(json);
Expand All @@ -84,6 +93,7 @@ describe('v5 access_token tests', () => {
]);
});

// Test the OAuth process for getting an access token
test('v5 access_token oauth user token', async() => {
const mock_api_config = jest.fn();
mock_api_config.app_id = 'test-app-id';
Expand Down Expand Up @@ -111,6 +121,7 @@ describe('v5 access_token tests', () => {

const read_scopes = [Scope.READ_USERS, Scope.READ_PINS];
await access_token.oauth({ scopes: read_scopes });
// verify the POST call and the response
expect(get_auth_code.mock.calls[0][0]).toBe(mock_api_config);
expect(get_auth_code.mock.calls[0][1]).toEqual({ scopes: read_scopes });
expect(got.post.mock.calls[0][0]).toEqual('test-api-uri/v5/oauth/token');
Expand All @@ -137,6 +148,7 @@ describe('v5 access_token tests', () => {
]);
});

// verify OAuth with client credentials
test('v5 access_token oauth client token', async() => {
const mock_api_config = jest.fn();
mock_api_config.app_id = 'test-app-id';
Expand Down Expand Up @@ -184,6 +196,7 @@ describe('v5 access_token tests', () => {
]);
});

// verify that the refresh token is not updated when it is not returned
test('v5 access_token refresh without refresh_token', async() => {
const mock_api_config = jest.fn();
mock_api_config.app_id = 'test-app-id';
Expand Down Expand Up @@ -239,6 +252,8 @@ describe('v5 access_token tests', () => {
]);
});

// verify that the refresh token is not updated when it is returned
// "chained refresh" refers to getting a new refresh token
test('v5 access_token refresh with chained refresh_token', async() => {
const mock_api_config = jest.fn();
mock_api_config.app_id = 'test-app-id';
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/ad_metrics_async_report.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('ad_metrics_async_report_common tests', () => {
jest.clearAllMocks();
});

// Test all of the common attributes that can be set on an AdMetricsAsyncReport
test('ad async report attributes', async() => {
const ad_async_report = new AdMetricsAsyncReport(
'test_api_config', 'test_access_token', 'test_advertiser_id')
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('ad_metrics_async_report_common tests', () => {
);
});

// Make sure that errors in attributes throw the appropriate exceptions
test('ad metrics async report attribute errors', async() => {
const ad_async_report = new AdMetricsAsyncReport(
'test_api_config', 'test_access_token', 'test_advertiser_id')
Expand Down
1 change: 1 addition & 0 deletions nodejs/src/advertisers.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('v5 advertisers tests', () => {
jest.clearAllMocks();
});

// Test the various kinds of ad objects that can be retrieved from the API
test('v5 advertisers', async() => {
const adv = new Advertisers('test_user', 'test_api_config', 'test_access_token');
expect(ApiObject.mock.instances.length).toBe(1);
Expand Down
4 changes: 4 additions & 0 deletions nodejs/src/analytics.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('v5 analytics tests', () => {
jest.clearAllMocks();
});

// Test requests for synchronous user (organic) reports
test('v5 user analytics', async() => {
const analytics = new UserAnalytics(
'test_user_id', 'test_api_config', 'test_access_token')
Expand All @@ -24,6 +25,7 @@ describe('v5 analytics tests', () => {
const mock_request_data = jest.spyOn(ApiObject.prototype, 'request_data');
mock_request_data.mockResolvedValue('test_response');

// do the GET request with reference to an ad account
expect(await analytics.get('test_ad_account'))
.toEqual('test_response');

Expand Down Expand Up @@ -51,6 +53,7 @@ start_date=2021-03-01&end_date=2021-03-31\
&split_field=PIN_FORMAT');
});

// Test requests for synchronous Pin (organic) reports
test('v5 pin analytics', async() => {
const analytics = new PinAnalytics(
'test_pin_id', 'test_api_config', 'test_access_token')
Expand Down Expand Up @@ -89,6 +92,7 @@ start_date=2021-03-01&end_date=2021-03-31\
&app_types=WEB&split_field=NO_SPLIT');
});

// Test requests for synchronous Ad reports on various kinds of ad objects
test('v5 ads analytics', async() => {
const analytics = new AdAnalytics('test_api_config', 'test_access_token')
.start_date('2021-03-01')
Expand Down
1 change: 1 addition & 0 deletions nodejs/src/analytics_attributes.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AnalyticsAttributes, AdAnalyticsAttributes } from './analytics_attributes.js';

// Test all of the different kinds of analytics attributes, including error cases
describe('analytics_attributes tests', () => {
test('analytics attributes', () => {
const attributes = new AnalyticsAttributes();
Expand Down
3 changes: 3 additions & 0 deletions nodejs/src/api_common.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// Common code for all API calls

// Errors to handle Pinterest API use cases
export class SpamError extends Error {
constructor(message) {
super(message);
Expand Down
4 changes: 4 additions & 0 deletions nodejs/src/api_common.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ApiCommon, RateLimitError, RequestFailedError, SpamError } from './api_common';

describe('api_common tests', () => {
// verify that typical output is correct
test('print_response', () => {
// check output
console.log = jest.fn();
Expand All @@ -15,6 +16,7 @@ describe('api_common tests', () => {
mock_response.body = 'test-response-body';
api_common.print_response(mock_response);

// verify request identifier printed at high verbosity
mock_api_config.verbosity = 3;
api_common.print_response(mock_response);

Expand All @@ -26,6 +28,7 @@ describe('api_common tests', () => {
]);
});

// verify output for different kinds of errors
test('print_and_throw_error', () => {
// check output
console.log = jest.fn();
Expand Down Expand Up @@ -85,6 +88,7 @@ describe('api_common tests', () => {
[error_message]
]);

// test situations where the schema of the response is not as expected
expect(() => {
api_common.print_and_throw_error(undefined);
}).toThrowError(new RequestFailedError('unknown error'));
Expand Down
3 changes: 3 additions & 0 deletions nodejs/src/api_config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ describe('ApiConfig test environment', () => {
process.env = SAVED_ENV;
});

// Verify the default API configuration and that the configuration
// can be set from the environment.

test('API configuration from defaults', () => {
// check output
console.log = jest.fn();
Expand Down
15 changes: 7 additions & 8 deletions nodejs/src/api_media_object.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { ApiMediaObject } from './api_media_object.js';
import fs from 'fs';

// Media upload uses the standard fs (file system) methods,
// so fs needs to be mocked to test this functionality.
jest.mock('fs');

// Need to mock the standard FormData object to test media upload.
const mockFormAppend = jest.fn();
const mockFormSubmit = jest.fn();
jest.mock('form-data', () => {
Expand All @@ -14,23 +17,18 @@ jest.mock('form-data', () => {
});
});

/*
* Tests for the generic ApiObject class that is used for all versions
* of the Pinterest API.
*
* Note: the reset_backoff and wait_backoff functions are tested with
* the classes that call these functions instead of testing them in
* this file.
*/
// Tests for functionality related to media upload.
describe('api_media_object tests', () => {
test('upload_media', async() => {
const api_media_object = new ApiMediaObject(jest.fn(), jest.fn());

// verify that the object forces upload_media to be overridden
await expect(async() => {
await api_media_object.upload_media('test_media');
}).rejects.toThrowError(new Error('upload_media() must be overridden'));
});

// Verify the different kinds of values for media id and related error cases.
test('media_to_media_id', async() => {
const api_media_object = new ApiMediaObject(jest.fn(), jest.fn());

Expand Down Expand Up @@ -72,6 +70,7 @@ describe('api_media_object tests', () => {
}).rejects.toThrowError(new Error('invalid media: -314159'));
});

// Verify that upload calls the standard fs methods as expected.
test('upload_file_multipart', async() => {
const api_config = jest.fn();
api_config.credentials_warning = jest.fn();
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/api_object.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ describe('api_object tests', () => {
.toBe('hello?good=bye&cruel=world&and=farewell');
});

// Verify basic object creation and usage.
test('v5 api_object', async() => {
const mock_api_config = jest.fn();
mock_api_config.api_uri = 'test_uri';
Expand All @@ -78,6 +79,7 @@ describe('api_object tests', () => {
expect(response).toEqual('test_response_data');
});

// Verify that generic bookmark functionality works.
test('v5 api_object_iterator', async() => {
const mock_api_config = jest.fn();
mock_api_config.api_uri = 'test_uri';
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/async_report.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ describe('async report tests', () => {
jest.clearAllMocks();
});

// Verify the basic request_report / wait_report process.
test('async report methods', async() => {
const mock_constructor = jest.spyOn(ApiObject.prototype, 'constructor');
const test_report1 = new AsyncReport(
Expand Down Expand Up @@ -36,6 +37,7 @@ describe('async report tests', () => {
]]);
});

// Verify that exponential backoff works when waiting for a report.
test('async report run', async() => {
const test_report2_url = '\
test_report2_url/x-y-z/metrics_report.txt?Very-long-credentials-string';
Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/board.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ describe('v5 board tests', () => {
jest.clearAllMocks();
});

// Verify all of the methods of the Board class.
test('v5 board methods methods', async() => {
const test_board = new Board('test_board_id', 'test_api_config', 'test_access_token');
expect(ApiObject.mock.instances.length).toBe(1);
expect(ApiObject.mock.calls[0]).toEqual(['test_api_config', 'test_access_token']);

// see the comment in user.test.js for an explanation of why spyOn is used here
const mock_request_data = jest.spyOn(ApiObject.prototype, 'request_data');
mock_request_data.mockResolvedValue('test_response');

Expand Down
1 change: 1 addition & 0 deletions nodejs/src/delivery_metrics.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ describe('delivery_metrics tests', () => {
jest.clearAllMocks();
});

// Verify that delivery metrics are fetched and printed correctly.
test('delivery metrics', async() => {
const test_dm = new DeliveryMetrics('test_api_config', 'test_access_token');
expect(ApiObject.mock.instances.length).toBe(1);
Expand Down
9 changes: 6 additions & 3 deletions nodejs/src/pin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ describe('v5 pin tests', () => {
expect(ApiMediaObject.mock.instances.length).toBe(1);
expect(ApiMediaObject.mock.calls[0]).toEqual(['test_api_config', 'test_access_token']);

// see the comment in user.test.js for an explanation of why spyOn is used here
const mock_request_data = jest.spyOn(ApiMediaObject.prototype, 'request_data');
mock_request_data.mockResolvedValue('test_response');

// test Pin retrieval
let response = await test_pin.get();
expect(mock_request_data.mock.calls[0][0]).toEqual('/v5/pins/test_pin_id');
expect(response).toEqual('test_response');
Expand All @@ -34,7 +36,7 @@ describe('v5 pin tests', () => {
}
};

// create pin without a section
// create Pin without a section
const mock_post_data = jest.spyOn(ApiMediaObject.prototype, 'post_data');
const created_data = { id: 'created_pin_id' };
mock_post_data.mockResolvedValue(created_data);
Expand Down Expand Up @@ -198,14 +200,14 @@ describe('v5 pin tests', () => {
expect(test_pin.pin_id).toEqual('created_pin_id');

await expect(async() => {
// second call to create
// second call to create results in an exception
await test_pin.create(pin_data, 'test_board_id', { media: 'file_name' });
}).rejects.toThrowError(
new Error('media upload 12345 failed')
);

await expect(async() => {
// third call to create
// third call to create results in an exception due to no status
await test_pin.create(pin_data, 'test_board_id', { media: 'file_name' });
}).rejects.toThrowError(
new Error('media upload 314159265 not found')
Expand Down Expand Up @@ -248,6 +250,7 @@ describe('v5 pin tests', () => {
]);
});

// verify the logic used to upload a media file
test('v5 upload media', async() => {
const test_pin = new Pin('test_pin_id', 'test_api_config', 'test_access_token');

Expand Down
2 changes: 2 additions & 0 deletions nodejs/src/terms.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ describe('v5 terms tests', () => {
jest.clearAllMocks();
});

// Verify the get and print methods provided for related terms

test('v5 related terms methods', async() => {
const test_terms = new Terms('test_api_config', 'test_access_token');
expect(ApiObject.mock.instances.length).toBe(1);
Expand Down
Loading
Loading