diff --git a/src/lib/auth.js b/src/lib/auth.js index 5087d5b8a..4622247c4 100644 --- a/src/lib/auth.js +++ b/src/lib/auth.js @@ -84,7 +84,19 @@ class Auth { if (err) { return cb(err); } - if (groups != null && groups != false) { + + // Expect: SKIP if groups is falsey and not an array + // with at least one item (truthy length) + // Expect: CONTINUE otherwise (will error if groups is not + // an array, but this is current behavior) + // Caveat: STRING (if valid) will pass successfully + // bug give unexpected results + // Info: Cannot use `== false to check falsey values` + if (!!groups && groups.length !== 0) { + // TODO: create a better understanding of expectations + if (typeof groups === 'string') { + throw new TypeError('invalid type for function'); + } return cb(err, authenticatedUser(user, groups)); } next(); diff --git a/test/unit/auth.spec.js b/test/unit/auth.spec.js index 950cbac0f..829ef257a 100644 --- a/test/unit/auth.spec.js +++ b/test/unit/auth.spec.js @@ -1,9 +1,10 @@ // @flow import Auth from '../../src/lib/auth'; -jest.mock('../../src/lib/auth'); // $FlowFixMe import configExample from './partials/config'; +// $FlowFixMe +import configPlugins from './partials/config/plugin'; import AppConfig from '../../src/lib/config'; import {setup} from '../../src/lib/logger'; @@ -19,7 +20,98 @@ describe('AuthTest', () => { const auth: IAuth = new Auth(config); expect(auth).toBeDefined(); - expect(Auth).toHaveBeenCalledTimes(1); }); -}); \ No newline at end of file + describe('authenticate', () => { + test('should utilize plugin', () => { + const config: Config = new AppConfig(configPlugins); + const auth: IAuth = new Auth(config); + + expect(auth).toBeDefined(); + + const callback = jest.fn(); + const result = [ "test" ]; + + // $FlowFixMe + auth.authenticate(1, null, callback); + // $FlowFixMe + auth.authenticate(null, result, callback); + + expect(callback.mock.calls).toHaveLength(2); + expect(callback.mock.calls[0][0]).toBe(1); + expect(callback.mock.calls[0][1]).toBeUndefined(); + expect(callback.mock.calls[1][0]).toBeNull(); + expect(callback.mock.calls[1][1].real_groups).toBe(result); + }); + + test('should skip falsy values', () => { + const config: Config = new AppConfig(configPlugins); + const auth: IAuth = new Auth(config); + + expect(auth).toBeDefined(); + + const callback = jest.fn(); + let index = 0; + + // as defined by https://developer.mozilla.org/en-US/docs/Glossary/Falsy + for (const value of [ false, 0, "", null, undefined, NaN ]) { + // $FlowFixMe + auth.authenticate(null, value, callback); + const call = callback.mock.calls[index++]; + expect(call[0]).toBeDefined(); + expect(call[1]).toBeUndefined(); + } + }); + + test('should error truthy non-array', () => { + const config: Config = new AppConfig(configPlugins); + const auth: IAuth = new Auth(config); + + expect(auth).toBeDefined(); + + const callback = jest.fn(); + + for (const value of [ true, 1, "test", { } ]) { + expect(function ( ) { + // $FlowFixMe + auth.authenticate(null, value, callback); + }).toThrow(TypeError); + expect(callback.mock.calls).toHaveLength(0); + } + }); + + test('should skip empty array', () => { + const config: Config = new AppConfig(configPlugins); + const auth: IAuth = new Auth(config); + + expect(auth).toBeDefined(); + + const callback = jest.fn(); + const value = [ ]; + + // $FlowFixMe + auth.authenticate(null, value, callback); + expect(callback.mock.calls).toHaveLength(1); + expect(callback.mock.calls[0][0]).toBeDefined(); + expect(callback.mock.calls[0][1]).toBeUndefined(); + }); + + test('should accept valid array', () => { + const config: Config = new AppConfig(configPlugins); + const auth: IAuth = new Auth(config); + + expect(auth).toBeDefined(); + + const callback = jest.fn(); + let index = 0; + + for (const value of [ [ "" ], [ "1" ], [ "0" ], ["000"] ]) { + // $FlowFixMe + auth.authenticate(null, value, callback); + const call = callback.mock.calls[index++]; + expect(call[0]).toBeNull(); + expect(call[1].real_groups).toBe(value); + } + }); + }) +}); diff --git a/test/unit/partials/config.js b/test/unit/partials/config/index.js similarity index 88% rename from test/unit/partials/config.js rename to test/unit/partials/config/index.js index 92d044625..99262b33e 100644 --- a/test/unit/partials/config.js +++ b/test/unit/partials/config/index.js @@ -1,5 +1,8 @@ + +import path from 'path'; + const config = { - storage: `${__dirname}/store/test-storage`, + storage: path.join(__dirname, '../store/test-storage'), uplinks: { 'npmjs': { 'url': 'https://registry.npmjs.org/' diff --git a/test/unit/partials/config/plugin.js b/test/unit/partials/config/plugin.js new file mode 100644 index 000000000..cc81f6c7a --- /dev/null +++ b/test/unit/partials/config/plugin.js @@ -0,0 +1,9 @@ + +import path from 'path'; + +module.exports = { + ...require('./index'), + auth: { + [`${path.join(__dirname, '../plugin/authenticate')}`]: { } + } +}; diff --git a/test/unit/partials/plugin/authenticate.js b/test/unit/partials/plugin/authenticate.js new file mode 100644 index 000000000..545980ed2 --- /dev/null +++ b/test/unit/partials/plugin/authenticate.js @@ -0,0 +1,10 @@ + +module.exports = function ( ) { + return { + authenticate ( user, pass, callback ) { + /* user and pass are used here to forward errors + and success types respectively for testing purposes */ + callback(user, pass); + } + }; +};