From 8bbedc933b2685522b1fb3eb5b2517596136587b Mon Sep 17 00:00:00 2001 From: Christopher Kelley <000@cranlabs.io> Date: Mon, 26 Mar 2018 09:20:12 -0400 Subject: [PATCH 1/2] [Close #628] Test and correct auth plugin values --- src/lib/auth.js | 14 ++- test/unit/auth.spec.js | 102 +++++++++++++++++- .../partials/{config.js => config/index.js} | 5 +- test/unit/partials/config/plugin.js | 9 ++ test/unit/partials/plugin/authenticate.js | 10 ++ 5 files changed, 135 insertions(+), 5 deletions(-) rename test/unit/partials/{config.js => config/index.js} (88%) create mode 100644 test/unit/partials/config/plugin.js create mode 100644 test/unit/partials/plugin/authenticate.js diff --git a/src/lib/auth.js b/src/lib/auth.js index 68d7f2975..622d0af4c 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..763aace09 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,102 @@ 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.length).toBe(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(); + let index = 0; + + for (const value of [ true, 1, "test", { } ]) { + expect(function ( ) { + // $FlowFixMe + auth.authenticate(null, value, callback); + }).toThrow(TypeError); + expect(callback.mock.calls.length).toBe(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.length).toBe(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); + } + }; +}; From 5c5af275ab4d2fcc412e06dce13d9e7d184ab967 Mon Sep 17 00:00:00 2001 From: Christopher Kelley <000@cranlabs.io> Date: Mon, 26 Mar 2018 13:51:14 -0400 Subject: [PATCH 2/2] fix: correct linter errors and warnings --- src/lib/auth.js | 4 ++-- test/unit/auth.spec.js | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/lib/auth.js b/src/lib/auth.js index 1209ac27e..4622247c4 100644 --- a/src/lib/auth.js +++ b/src/lib/auth.js @@ -94,8 +94,8 @@ class Auth { // 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"); + if (typeof groups === 'string') { + throw new TypeError('invalid type for function'); } return cb(err, authenticatedUser(user, groups)); } diff --git a/test/unit/auth.spec.js b/test/unit/auth.spec.js index 763aace09..829ef257a 100644 --- a/test/unit/auth.spec.js +++ b/test/unit/auth.spec.js @@ -37,7 +37,7 @@ describe('AuthTest', () => { // $FlowFixMe auth.authenticate(null, result, callback); - expect(callback.mock.calls.length).toBe(2); + 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(); @@ -70,14 +70,13 @@ describe('AuthTest', () => { expect(auth).toBeDefined(); const callback = jest.fn(); - let index = 0; for (const value of [ true, 1, "test", { } ]) { expect(function ( ) { // $FlowFixMe auth.authenticate(null, value, callback); }).toThrow(TypeError); - expect(callback.mock.calls.length).toBe(0); + expect(callback.mock.calls).toHaveLength(0); } }); @@ -92,7 +91,7 @@ describe('AuthTest', () => { // $FlowFixMe auth.authenticate(null, value, callback); - expect(callback.mock.calls.length).toBe(1); + expect(callback.mock.calls).toHaveLength(1); expect(callback.mock.calls[0][0]).toBeDefined(); expect(callback.mock.calls[0][1]).toBeUndefined(); }); @@ -115,7 +114,4 @@ describe('AuthTest', () => { } }); }) - - - });