Skip to content

Commit 9496a79

Browse files
authored
Refactor improve typescript coverage (#22)
Refactor improve typescript coverage
2 parents d5cb9d4 + 836778a commit 9496a79

File tree

12 files changed

+178
-199
lines changed

12 files changed

+178
-199
lines changed

.huskyrc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"hooks": {
3+
"pre-commit": "yarn lint && yarn test",
4+
"commitmsg": "commitlint -e $GIT_PARAMS"
5+
}
6+
}
File renamed without changes.

dist/src/index.d.ts renamed to dist/index.d.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,11 @@ declare class LinkSDK {
3939
private domains;
4040
private params;
4141
private oauthParams;
42-
init(config: IConfig): void;
43-
authorize(options?: IMyAccountOptions): void;
44-
openVault(options?: IVaultOptions): void;
45-
openSettings(options?: IMyAccountOptions): void;
42+
private isInitialized;
43+
init({ clientId, scope, isTestEnvironment, redirectUri, continueTo, responseType, locale, state }: IConfig): void;
44+
authorize({ newTab, email, authPage, backTo, showAuthToggle }?: IMyAccountOptions): void;
45+
openVault({ newTab, backTo }?: IVaultOptions): void;
46+
openSettings({ newTab, backTo }?: IMyAccountOptions): void;
4647
}
4748
declare const _default: LinkSDK;
4849
export default _default;

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jest.config.js

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
const packageJSON = require('./package.json');
22

33
module.exports = {
4-
errorOnDeprecated: true,
54
moduleFileExtensions: ['ts', 'js'],
6-
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.ts$',
7-
testPathIgnorePatterns: [
8-
'/node_modules/',
9-
'(/__tests__/.*|(\\.|/)(test|spec))\\.d\.ts$'
10-
],
5+
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(tsx?)$',
6+
testPathIgnorePatterns: ['/node_modules/', '(/__tests__/.*|(\\.|/)(test|spec))\\.d.ts$'],
117
transform: {
12-
'.ts': 'ts-jest'
8+
'^.+\\.tsx?$': 'ts-jest'
139
},
1410
collectCoverage: true,
1511
coverageDirectory: '<rootDir>/jest/coverage',
16-
coveragePathIgnorePatterns: [
17-
'/__tests__/'
18-
],
12+
coveragePathIgnorePatterns: ['/__tests__/'],
13+
errorOnDeprecated: true,
1914
globals: {
2015
VERSION: packageJSON.version
2116
}

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
"prepareRelease": "npm run build && git add dist",
1515
"createChangelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md",
1616
"version": "npm run prepareRelease && npm run createChangelog",
17-
"precommit": "yarn lint && yarn test",
18-
"commitmsg": "commitlint -e $GIT_PARAMS",
1917
"test": "jest",
2018
"lint": "tslint --project tsconfig.json"
2119
},
@@ -30,11 +28,11 @@
3028
"@types/jest": "^24.0.23",
3129
"@types/node-fetch": "^2.5.4",
3230
"@types/qs": "^6.9.0",
33-
"awesome-typescript-loader": "^5.2.0",
3431
"husky": "^3.1.0",
3532
"jest": "^24.9.0",
3633
"node-fetch": "^2.5.0",
3734
"ts-jest": "^24.2.0",
35+
"ts-loader": "^6.2.1",
3836
"tslint": "^5.20.1",
3937
"typescript": "^3.7.3",
4038
"webpack": "^4.41.2",

src/@types/constants.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
declare const VERSION: string;
1+
declare const VERSION: string;

src/__tests__/index.ts

Lines changed: 24 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,15 @@ import linkSDK, { IParams, IDomains, IOauthParams } from '..';
22
import { DOMAIN, VAULT, MY_ACCOUNT } from '../endpoints';
33
import * as packageJSON from '../../package.json';
44

5-
describe('LinkSDK', () => {
6-
const value = 'test';
7-
const mockValue = {} as { params: IParams; domains: IDomains, oauthParams: IOauthParams };
5+
const value = 'test';
6+
const mockValue = {} as { params: IParams; domains: IDomains; oauthParams: IOauthParams };
87

8+
describe('LinkSDK', () => {
99
describe('init', () => {
1010
test('no clientId', async () => {
11-
const errorTracker = jest.fn();
12-
13-
try {
11+
expect(() => {
1412
linkSDK.init({ clientId: '' });
15-
} catch (error) {
16-
errorTracker(error);
17-
}
18-
19-
expect(errorTracker).toBeCalled();
13+
}).toThrow('Need a clientId to initialize');
2014
});
2115

2216
test('default', async () => {
@@ -109,14 +103,10 @@ describe('LinkSDK', () => {
109103
});
110104

111105
describe('authorize', () => {
112-
test('Calling "authorize" method before an init will failed', async () => {
113-
try {
106+
test('Calling "authorize" method before an init will fail', async () => {
107+
expect(() => {
114108
linkSDK.authorize();
115-
116-
throw new Error('failed');
117-
} catch (error) {
118-
expect(error.message).not.toBe('failed');
119-
}
109+
}).toThrow('SDK not initialized');
120110
});
121111

122112
test('default params', async () => {
@@ -125,12 +115,12 @@ describe('LinkSDK', () => {
125115
linkSDK.init.call(mockValue, {
126116
clientId: value
127117
});
118+
// @ts-ignore Ignores missing arguments to test user passing no arguments
128119
linkSDK.authorize.call(mockValue);
129120

130121
expect(open).toBeCalled();
131122

132-
const url = open.mock.calls[0][0];
133-
const isNewTab = open.mock.calls[0][1];
123+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
134124

135125
const host = `https://${mockValue.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}`;
136126
expect(url).toContain(host);
@@ -162,32 +152,27 @@ describe('LinkSDK', () => {
162152

163153
expect(open).toBeCalled();
164154

165-
const isNewTab = open.mock.calls[0][1];
155+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
166156
expect(isNewTab).toBe('_blank');
167157

168-
const url = open.mock.calls[0][0];
169158
const { params, domains, oauthParams } = mockValue;
170159
const host = `https://${domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}`;
171160
const qs =
172161
`client_id=${params.client_id}&redirect_uri=${encodeURIComponent(oauthParams.redirect_uri)}` +
173162
`&response_type=token&scope=${value}`;
174163
const configs = encodeURIComponent(
175-
`email=${email};sdk_platform=js;sdk_version=${packageJSON.version};auth_action=${authPage}`
164+
`sdk_platform=js;sdk_version=${packageJSON.version};email=${email};auth_action=${authPage}`
176165
);
177166

178167
expect(url).toBe(`${host}?${qs}&configs=${configs}`);
179168
});
180169
});
181170

182171
describe('openVault', () => {
183-
test('Calling "openVault" method before an init will failed', async () => {
184-
try {
172+
test('Calling "openVault" method before an init will fail', async () => {
173+
expect(() => {
185174
linkSDK.openVault();
186-
187-
throw new Error('failed');
188-
} catch (error) {
189-
expect(error.message).not.toBe('failed');
190-
}
175+
}).toThrow('SDK not initialized');
191176
});
192177

193178
test('default params', async () => {
@@ -197,12 +182,12 @@ describe('LinkSDK', () => {
197182
clientId: value,
198183
scope: [value]
199184
});
185+
// @ts-ignore Ignores missing arguments to test user passing no arguments
200186
linkSDK.openVault.call(mockValue);
201187

202188
expect(open).toBeCalled();
203189

204-
const url = open.mock.calls[0][0];
205-
const isNewTab = open.mock.calls[0][1];
190+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
206191

207192
const host = `https://${mockValue.domains.vault}`;
208193
expect(url).toContain(host);
@@ -231,10 +216,9 @@ describe('LinkSDK', () => {
231216

232217
expect(open).toBeCalled();
233218

234-
const isNewTab = open.mock.calls[0][1];
219+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
235220
expect(isNewTab).toBe('_blank');
236221

237-
const url = open.mock.calls[0][0];
238222
const { params, domains } = mockValue;
239223
const host = `https://${domains.vault}`;
240224
const qs = `client_id=${params.client_id}`;
@@ -246,13 +230,10 @@ describe('LinkSDK', () => {
246230

247231
describe('openSettings', () => {
248232
test('Calling "openSettings" method before an init will failed', async () => {
249-
try {
233+
expect(() => {
234+
// @ts-ignore Ignores missing arguments to test user passing no arguments
250235
linkSDK.openSettings();
251-
252-
throw new Error('failed');
253-
} catch (error) {
254-
expect(error.message).not.toBe('failed');
255-
}
236+
}).toThrow('SDK not initialized');
256237
});
257238

258239
test('default params', async () => {
@@ -262,12 +243,12 @@ describe('LinkSDK', () => {
262243
clientId: value,
263244
scope: [value]
264245
});
246+
// @ts-ignore Ignores missing arguments to test user passing no arguments
265247
linkSDK.openSettings.call(mockValue);
266248

267249
expect(open).toBeCalled();
268250

269-
const url = open.mock.calls[0][0];
270-
const isNewTab = open.mock.calls[0][1];
251+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
271252

272253
const host = `https://${mockValue.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}`;
273254
expect(url).toContain(host);
@@ -296,10 +277,9 @@ describe('LinkSDK', () => {
296277

297278
expect(open).toBeCalled();
298279

299-
const isNewTab = open.mock.calls[0][1];
280+
const [[url, isNewTab]] = open.mock.calls; // [0][1]
300281
expect(isNewTab).toBe('_blank');
301282

302-
const url = open.mock.calls[0][0];
303283
const { params, domains } = mockValue;
304284
const host = `https://${domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}`;
305285
const qs = `client_id=${params.client_id}`;

src/index.ts

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as qs from 'qs';
1+
import { stringify } from 'qs';
22

33
import { DOMAIN, MY_ACCOUNT, VAULT } from './endpoints';
44

@@ -45,31 +45,45 @@ interface IMyAccountOptions {
4545
showAuthToggle?: boolean;
4646
}
4747

48-
function encodeConfigWithParams(params: any, configs: { [k: string]: string | boolean | undefined }) {
49-
const endcodedConfigs = qs.stringify(configs, { delimiter: ';', encode: false });
50-
return qs.stringify({ ...params, configs: endcodedConfigs });
48+
interface IUrlConfig {
49+
email?: string;
50+
auth_action?: string;
51+
show_auth_toggle?: boolean;
52+
}
53+
54+
const commonUrlConfig = {
55+
sdk_platform: 'js',
56+
sdk_version: VERSION
57+
};
58+
59+
type ICommonUrlConfig = typeof commonUrlConfig & { back_to?: string };
60+
61+
function encodeConfigWithParams<Params, Configs>(params: Params, configs: Configs) {
62+
const encodedConfigs = stringify(configs, { delimiter: ';', encode: false });
63+
return stringify({ ...params, configs: encodedConfigs }, { addQueryPrefix: true });
5164
}
5265

5366
class LinkSDK {
5467
private domains: IDomains;
5568
private params: IParams;
5669
private oauthParams: IOauthParams;
5770

58-
public init(config: IConfig): void {
59-
if (!config.clientId) {
60-
throw new Error('Need a clientId to initialise');
71+
private isInitialized: boolean = false;
72+
73+
public init({
74+
clientId,
75+
scope = [],
76+
isTestEnvironment,
77+
redirectUri = `${location.protocol}//${location.host}/callback`,
78+
continueTo,
79+
responseType = 'token',
80+
locale,
81+
state
82+
}: IConfig): void {
83+
if (!clientId) {
84+
throw new Error('Need a clientId to initialize');
6185
}
6286

63-
const {
64-
clientId,
65-
redirectUri = `${location.protocol}//${location.host}/callback`,
66-
responseType = 'token',
67-
scope = [],
68-
locale,
69-
state,
70-
continueTo
71-
} = config;
72-
7387
this.params = {
7488
client_id: clientId,
7589
locale,
@@ -84,59 +98,63 @@ class LinkSDK {
8498
state
8599
};
86100

87-
const subdomain = config.isTestEnvironment ? 'TEST_SUBDOMAIN' : 'SUBDOMAIN';
101+
const subdomain = isTestEnvironment ? 'TEST_SUBDOMAIN' : 'SUBDOMAIN';
88102
this.domains = {
89103
vault: `${VAULT[subdomain]}.${DOMAIN}`,
90104
myaccount: `${MY_ACCOUNT[subdomain]}.${DOMAIN}`
91105
};
106+
107+
this.isInitialized = true;
92108
}
93109

94110
// Open My Account to authorize application to use MtLink API
95-
public authorize(options: IMyAccountOptions = {}): void {
96-
const { newTab = false, email, authPage, backTo, showAuthToggle } = options;
111+
public authorize({ newTab = false, email, authPage, backTo, showAuthToggle }: IMyAccountOptions = {}): void {
112+
if (!this.isInitialized) {
113+
throw new Error('SDK not initialized');
114+
}
97115

98-
const params = encodeConfigWithParams(
116+
const params = encodeConfigWithParams<IParams | IOauthParams, ICommonUrlConfig & IUrlConfig>(
99117
{ ...this.oauthParams, ...this.params },
100118
{
119+
...commonUrlConfig,
101120
email,
102-
sdk_platform: 'js',
103-
sdk_version: VERSION,
104121
auth_action: authPage,
105122
back_to: backTo,
106123
show_auth_toggle: showAuthToggle
107124
}
108125
);
109126

110-
window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}?${params}`, newTab ? '_blank' : '_self');
127+
window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.OAUTH}${params}`, newTab ? '_blank' : '_self');
111128
}
112129

113130
// Open the Vault page
114-
public openVault(options: IVaultOptions = {}): void {
115-
const { newTab = false, backTo = location.href } = options;
116-
const params = encodeConfigWithParams(this.params, {
117-
sdk_platform: 'js',
118-
sdk_version: VERSION,
131+
public openVault({ newTab = false, backTo = location.href }: IVaultOptions = {}): void {
132+
if (!this.isInitialized) {
133+
throw new Error('SDK not initialized');
134+
}
135+
136+
const params = encodeConfigWithParams<IParams, ICommonUrlConfig>(this.params, {
137+
...commonUrlConfig,
119138
back_to: backTo
120139
});
121140

122-
window.open(`https://${this.domains.vault}?${params}`, newTab ? '_blank' : '_self');
141+
window.open(`https://${this.domains.vault}${params}`, newTab ? '_blank' : '_self');
123142
}
124143

125144
// Open the Guest settings page
126-
public openSettings(options: IMyAccountOptions = {}): void {
127-
const { newTab = false, backTo = location.href } = options;
145+
public openSettings({ newTab = false, backTo = location.href }: IMyAccountOptions = {}): void {
146+
if (!this.isInitialized) {
147+
throw new Error('SDK not initialized');
148+
}
128149

129-
const params = encodeConfigWithParams(this.params, {
130-
sdk_platform: 'js',
131-
sdk_version: VERSION,
150+
const params = encodeConfigWithParams<IParams, ICommonUrlConfig>(this.params, {
151+
...commonUrlConfig,
132152
back_to: backTo
133153
});
134154

135-
window.open(
136-
`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}?${params}`,
137-
newTab ? '_blank' : '_self'
138-
);
155+
window.open(`https://${this.domains.myaccount}/${MY_ACCOUNT.PATHS.SETTINGS}${params}`, newTab ? '_blank' : '_self');
139156
}
140157
}
141158

159+
// Probably there is no need for this to be a class if initialized here.
142160
export default new LinkSDK();

0 commit comments

Comments
 (0)