Skip to content

Commit 19c6604

Browse files
committed
Move to Typescript tests
1 parent afc46ee commit 19c6604

File tree

8 files changed

+750
-103
lines changed

8 files changed

+750
-103
lines changed

.nycrc.json

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
{
2-
"check-coverage": true,
3-
"per-file": false,
4-
"lines": 5,
5-
"statements": 5,
6-
"functions": 5,
7-
"branches": 5,
8-
"include": [
9-
"lib/**/*.js"
2+
"extends": "@istanbuljs/nyc-config-typescript",
3+
"all": true,
4+
"extension": [
5+
".ts"
106
],
117
"exclude": [
8+
"dist/**",
9+
"test/**",
10+
"functions/**",
11+
"migrations/**",
12+
"node_modules/**",
13+
"debug/**",
14+
"coverage/**",
15+
"**/*.spec.ts",
16+
".eastrc.js"
1217
],
1318
"reporter": [
14-
"lcov",
15-
"text",
16-
"text-summary"
17-
],
18-
"require": [
19-
],
20-
"extension": [
21-
],
22-
"all": true
19+
"json",
20+
"text"
21+
]
2322
}

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"description": "Brightspace authentication strategy for Passport.",
55
"scripts": {
66
"build": "tsc",
7-
"test": "mocha 'test/*.test.js'",
8-
"test:cov": "nyc mocha 'test/*.test.js'",
7+
"test": "ts-mocha 'test/*.test.ts'",
8+
"test:cov": "nyc ts-mocha 'test/*.test.ts'",
99
"prepublish": "yarn build"
1010
},
1111
"keywords": [
@@ -35,6 +35,10 @@
3535
"devDependencies": {
3636
"@feedbackfruits/eslint-config": "2.0.1",
3737
"@feedbackfruits/tsconfig": "1.0.2",
38+
"@istanbuljs/nyc-config-typescript": "1.0.2",
39+
"@types/chai": "5.2.2",
40+
"@types/expect": "24.3.2",
41+
"@types/mocha": "10.0.10",
3842
"@types/passport-oauth2": "1.4.17",
3943
"@typescript-eslint/eslint-plugin": "8.34.1",
4044
"@typescript-eslint/parser": "8.34.1",
@@ -45,6 +49,9 @@
4549
"nyc": "17.1.0",
4650
"passport": "^0.7.0",
4751
"sinon": "^21.0.0",
52+
"ts-mocha": "11.1.0",
53+
"ts-node": "10.9.2",
54+
"tsconfig-paths": "4.2.0",
4855
"typescript": "5.8.3"
4956
},
5057
"engines": {
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
const passport = require('passport');
2-
const BrightspaceStrategy = require('../dist/strategy').default;
3-
const { expect, assert } = require('chai');
1+
// @ts-nocheck
2+
import BrightspaceStrategy from '../src';
3+
import passport from 'passport';
4+
import { expect, assert } from 'chai';
45

56
describe('Strategy Integration with Passport', function() {
67
beforeEach(function() {

test/strategy.oauth.test.js

Lines changed: 0 additions & 71 deletions
This file was deleted.

test/strategy.oauth.test.ts

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// @ts-nocheck
2+
import BrightspaceStrategy from '../src';
3+
import { expect } from 'chai';
4+
5+
describe('Strategy OAuth Configuration', function() {
6+
let strategy;
7+
8+
beforeEach(function() {
9+
strategy = new BrightspaceStrategy({
10+
host: 'https://api.brightspace.im',
11+
clientID: 'ABC123',
12+
clientSecret: 'secret'
13+
}, function() {});
14+
});
15+
16+
describe('OAuth2 configuration', function() {
17+
it('should configure OAuth2 to use authorization header for GET requests', function() {
18+
expect(strategy._oauth2._useAuthorizationHeaderForGET).to.be.true;
19+
});
20+
21+
it('should have overridden getOAuthAccessToken method', function() {
22+
expect(strategy._oauth2.getOAuthAccessToken).to.be.a('function');
23+
// The method should be different from the default OAuth2Strategy method
24+
expect(strategy._oauth2.getOAuthAccessToken.toString()).to.include('Basic');
25+
});
26+
27+
it('should have access token URL configured', function() {
28+
expect(strategy._oauth2._getAccessTokenUrl).to.be.a('function');
29+
});
30+
});
31+
32+
describe('URL configuration', function() {
33+
it('should set correct authorization URL', function() {
34+
expect(strategy._oauth2._authorizeUrl).to.equal('https://auth.brightspace.com/oauth2/auth');
35+
});
36+
37+
it('should set correct access token URL', function() {
38+
expect(strategy._oauth2._accessTokenUrl).to.equal('https://auth.brightspace.com/core/connect/token');
39+
});
40+
41+
it('should allow custom URLs', function() {
42+
const customStrategy = new BrightspaceStrategy({
43+
host: 'https://api.brightspace.im',
44+
clientID: 'ABC123',
45+
clientSecret: 'secret',
46+
authorizationURL: 'https://custom.brightspace.com/oauth2/auth',
47+
tokenURL: 'https://custom.brightspace.com/oauth2/token'
48+
}, function() {});
49+
50+
expect(customStrategy._oauth2._authorizeUrl).to.equal('https://custom.brightspace.com/oauth2/auth');
51+
expect(customStrategy._oauth2._accessTokenUrl).to.equal('https://custom.brightspace.com/oauth2/token');
52+
});
53+
});
54+
55+
describe('client credentials configuration', function() {
56+
it('should store client ID and secret', function() {
57+
expect(strategy._oauth2._clientId).to.equal('ABC123');
58+
expect(strategy._oauth2._clientSecret).to.equal('secret');
59+
});
60+
61+
it('should configure different client credentials', function() {
62+
const differentStrategy = new BrightspaceStrategy({
63+
host: 'https://api.brightspace.im',
64+
clientID: 'XYZ789',
65+
clientSecret: 'different-secret'
66+
}, function() {});
67+
68+
expect(differentStrategy._oauth2._clientId).to.equal('XYZ789');
69+
expect(differentStrategy._oauth2._clientSecret).to.equal('different-secret');
70+
});
71+
});
72+
73+
describe('getOAuthAccessToken method override', function() {
74+
let strategy;
75+
let originalRequest;
76+
77+
beforeEach(function() {
78+
strategy = new BrightspaceStrategy({
79+
host: 'https://api.brightspace.im',
80+
clientID: 'ABC123',
81+
clientSecret: 'secret'
82+
}, function() {});
83+
84+
// Mock the internal _request method
85+
originalRequest = strategy._oauth2._request;
86+
});
87+
88+
afterEach(function() {
89+
if (originalRequest) {
90+
strategy._oauth2._request = originalRequest;
91+
}
92+
});
93+
94+
it('should handle successful JSON token response', function(done) {
95+
const mockTokenResponse = {
96+
access_token: 'mock_access_token',
97+
refresh_token: 'mock_refresh_token',
98+
token_type: 'Bearer',
99+
expires_in: 3600
100+
};
101+
102+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
103+
expect(method).to.equal('POST');
104+
expect(headers['Content-Type']).to.equal('application/x-www-form-urlencoded');
105+
expect(headers['Authorization']).to.include('Basic');
106+
107+
// Verify the Authorization header contains base64 encoded client credentials
108+
const expectedAuth = 'Basic ' + Buffer.from('ABC123:secret').toString('base64');
109+
expect(headers['Authorization']).to.equal(expectedAuth);
110+
111+
callback(null, JSON.stringify(mockTokenResponse), null);
112+
};
113+
114+
strategy._oauth2.getOAuthAccessToken('authorization_code', {}, function(error, accessToken, refreshToken, results) {
115+
expect(error).to.be.null;
116+
expect(accessToken).to.equal('mock_access_token');
117+
expect(refreshToken).to.equal('mock_refresh_token');
118+
expect(results.token_type).to.equal('Bearer');
119+
expect(results.expires_in).to.equal(3600);
120+
expect(results.refresh_token).to.be.undefined; // Should be deleted from results
121+
done();
122+
});
123+
});
124+
125+
it('should handle URL-encoded token response fallback', function(done) {
126+
const urlEncodedResponse = 'access_token=url_encoded_token&refresh_token=url_refresh_token&token_type=Bearer&expires_in=7200';
127+
128+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
129+
// Simulate a response that's not valid JSON but is URL-encoded
130+
callback(null, urlEncodedResponse, null);
131+
};
132+
133+
strategy._oauth2.getOAuthAccessToken('authorization_code', {}, function(error, accessToken, refreshToken, results) {
134+
expect(error).to.be.null;
135+
expect(accessToken).to.equal('url_encoded_token');
136+
expect(refreshToken).to.equal('url_refresh_token');
137+
expect(results.token_type).to.equal('Bearer');
138+
expect(results.expires_in).to.equal('7200');
139+
expect(results.refresh_token).to.be.undefined; // Should be deleted from results
140+
done();
141+
});
142+
});
143+
144+
it('should handle refresh token flow', function(done) {
145+
const mockTokenResponse = {
146+
access_token: 'new_access_token',
147+
refresh_token: 'new_refresh_token',
148+
token_type: 'Bearer'
149+
};
150+
151+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
152+
expect(data).to.include('refresh_token=old_refresh_token');
153+
expect(data).to.include('grant_type=refresh_token');
154+
callback(null, JSON.stringify(mockTokenResponse), null);
155+
};
156+
157+
strategy._oauth2.getOAuthAccessToken('old_refresh_token', { grant_type: 'refresh_token' }, function(error, accessToken, refreshToken, results) {
158+
expect(error).to.be.null;
159+
expect(accessToken).to.equal('new_access_token');
160+
expect(refreshToken).to.equal('new_refresh_token');
161+
done();
162+
});
163+
});
164+
165+
it('should handle authorization code flow', function(done) {
166+
const mockTokenResponse = {
167+
access_token: 'code_access_token',
168+
refresh_token: 'code_refresh_token'
169+
};
170+
171+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
172+
expect(data).to.include('code=authorization_code_value');
173+
expect(data).not.to.include('grant_type=refresh_token');
174+
callback(null, JSON.stringify(mockTokenResponse), null);
175+
};
176+
177+
strategy._oauth2.getOAuthAccessToken('authorization_code_value', {}, function(error, accessToken, refreshToken, results) {
178+
expect(error).to.be.null;
179+
expect(accessToken).to.equal('code_access_token');
180+
expect(refreshToken).to.equal('code_refresh_token');
181+
done();
182+
});
183+
});
184+
185+
it('should handle callback function as second parameter', function(done) {
186+
const mockTokenResponse = {
187+
access_token: 'callback_token',
188+
refresh_token: 'callback_refresh'
189+
};
190+
191+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
192+
callback(null, JSON.stringify(mockTokenResponse), null);
193+
};
194+
195+
// Test overload where second parameter is the callback
196+
strategy._oauth2.getOAuthAccessToken('test_code', function(error, accessToken, refreshToken, results) {
197+
expect(error).to.be.null;
198+
expect(accessToken).to.equal('callback_token');
199+
expect(refreshToken).to.equal('callback_refresh');
200+
done();
201+
});
202+
});
203+
204+
it('should handle network errors', function(done) {
205+
const networkError = new Error('Network connection failed');
206+
207+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
208+
callback(networkError);
209+
};
210+
211+
strategy._oauth2.getOAuthAccessToken('test_code', {}, function(error, accessToken, refreshToken, results) {
212+
expect(error).to.equal(networkError);
213+
expect(accessToken).to.be.undefined;
214+
expect(refreshToken).to.be.undefined;
215+
expect(results).to.be.undefined;
216+
done();
217+
});
218+
});
219+
220+
it('should handle malformed JSON gracefully with URL-encoded fallback', function(done) {
221+
const malformedResponse = 'access_token=fallback_token&malformed=json{incomplete';
222+
223+
strategy._oauth2._request = function(method, url, headers, data, accessToken, callback) {
224+
callback(null, malformedResponse, null);
225+
};
226+
227+
strategy._oauth2.getOAuthAccessToken('test_code', {}, function(error, accessToken, refreshToken, results) {
228+
expect(error).to.be.null;
229+
expect(accessToken).to.equal('fallback_token');
230+
expect(results.malformed).to.equal('json{incomplete');
231+
done();
232+
});
233+
});
234+
});
235+
});
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
const BrightspaceStrategy = require('../dist/strategy').default;
2-
const { expect, assert } = require('chai');
1+
// @ts-nocheck
2+
import BrightspaceStrategy from '../src';
3+
import { expect, assert } from 'chai';
34

45
describe('Strategy#userProfile', function () {
56
var strategy = new BrightspaceStrategy({

0 commit comments

Comments
 (0)