initial commit of user code, added in test framework and user test

This commit is contained in:
alex-phillips 2020-02-14 10:02:18 -05:00
parent cdf79a3bf8
commit 7bee88e383
9 changed files with 5087 additions and 4 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
node_modules/
coverage/
dev.db
test.db

View File

@ -4,7 +4,8 @@
"password": null,
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql",
"dialect": "sqlite",
"storage": "dev.db",
"operatorsAliases": false
},
"test": {
@ -12,7 +13,8 @@
"password": null,
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql",
"dialect": "sqlite",
"storage": "test.db",
"operatorsAliases": false
},
"production": {

188
jest.config.js Normal file
View File

@ -0,0 +1,188 @@
// For a detailed explanation regarding each configuration property, visit:
// https://jestjs.io/docs/en/configuration.html
module.exports = {
// All imported modules in your tests should be mocked automatically
// automock: false,
// Stop running tests after `n` failures
// bail: 0,
// Respect "browser" field in package.json when resolving modules
// browser: false,
// The directory where Jest should store its cached dependency information
// cacheDirectory: "/tmp/jest_rs",
// Automatically clear mock calls and instances between every test
clearMocks: true,
// Indicates whether the coverage information should be collected while executing the test
// collectCoverage: false,
// An array of glob patterns indicating a set of files for which coverage information should be collected
// collectCoverageFrom: undefined,
// The directory where Jest should output its coverage files
coverageDirectory: "coverage",
// An array of regexp pattern strings used to skip coverage collection
// coveragePathIgnorePatterns: [
// "/node_modules/"
// ],
// A list of reporter names that Jest uses when writing coverage reports
// coverageReporters: [
// "json",
// "text",
// "lcov",
// "clover"
// ],
// An object that configures minimum threshold enforcement for coverage results
// coverageThreshold: undefined,
// A path to a custom dependency extractor
// dependencyExtractor: undefined,
// Make calling deprecated APIs throw helpful error messages
// errorOnDeprecated: false,
// Force coverage collection from ignored files using an array of glob patterns
// forceCoverageMatch: [],
// A path to a module which exports an async function that is triggered once before all test suites
// globalSetup: undefined,
// A path to a module which exports an async function that is triggered once after all test suites
// globalTeardown: undefined,
// A set of global variables that need to be available in all test environments
// globals: {},
// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers.
// maxWorkers: "50%",
// An array of directory names to be searched recursively up from the requiring module's location
// moduleDirectories: [
// "node_modules"
// ],
// An array of file extensions your modules use
// moduleFileExtensions: [
// "js",
// "json",
// "jsx",
// "ts",
// "tsx",
// "node"
// ],
// A map from regular expressions to module names that allow to stub out resources with a single module
// moduleNameMapper: {},
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
// Activates notifications for test results
// notify: false,
// An enum that specifies notification mode. Requires { notify: true }
// notifyMode: "failure-change",
// A preset that is used as a base for Jest's configuration
// preset: undefined,
// Run tests from one or more projects
// projects: undefined,
// Use this configuration option to add custom reporters to Jest
// reporters: undefined,
// Automatically reset mock state between every test
// resetMocks: false,
// Reset the module registry before running each individual test
// resetModules: false,
// A path to a custom resolver
// resolver: undefined,
// Automatically restore mock state between every test
// restoreMocks: false,
// The root directory that Jest should scan for tests and modules within
// rootDir: undefined,
// A list of paths to directories that Jest should use to search for files in
// roots: [
// "<rootDir>"
// ],
// Allows you to use a custom runner instead of Jest's default test runner
// runner: "jest-runner",
// The paths to modules that run some code to configure or set up the testing environment before each test
// setupFiles: [],
// A list of paths to modules that run some code to configure or set up the testing framework before each test
// setupFilesAfterEnv: [],
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
// snapshotSerializers: [],
// The test environment that will be used for testing
testEnvironment: "node",
// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
// Adds a location field to test results
// testLocationInResults: false,
// The glob patterns Jest uses to detect test files
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
// This option allows the use of a custom results processor
// testResultsProcessor: undefined,
// This option allows use of a custom test runner
// testRunner: "jasmine2",
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
// testURL: "http://localhost",
// Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout"
// timers: "real",
// A map from regular expressions to paths to transformers
// transform: undefined,
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
// transformIgnorePatterns: [
// "/node_modules/"
// ],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,
// Indicates whether each individual test should be reported during the run
// verbose: undefined,
// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode
// watchPathIgnorePatterns: [],
// Whether to use watchman for file crawling
// watchman: true,
};

View File

@ -0,0 +1,40 @@
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
username: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true
},
avatar: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
created_at: {
allowNull: false,
type: Sequelize.DATE
},
updated_at: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('users');
}
};

View File

@ -21,7 +21,8 @@ fs
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = sequelize['import'](path.join(__dirname, file));
// const model = sequelize['import'](path.join(__dirname, file));
const model = require(path.join(__dirname, file)).init(sequelize, Sequelize)
db[model.name] = model;
});

30
models/user.js Normal file
View File

@ -0,0 +1,30 @@
'use strict';
const {Model} = require('sequelize');
const bcrypt = require('bcrypt');
class User extends Model {
static init(sequelize, DataTypes) {
return super.init({
username: DataTypes.STRING,
email: DataTypes.STRING,
avatar: DataTypes.STRING,
password: {
type: DataTypes.STRING,
set (val) {
this.setDataValue('password', bcrypt.hashSync(val, 10));
}
}
}, {
sequelize,
underscored: true,
tableName: 'users',
})
}
verifyPassword(check) {
return bcrypt.compareSync(check, this.password);
}
}
module.exports = User;

4776
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,10 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"db:migrate": "sequelize-cli db:migrate",
"pretest": "NODE_ENV=test npm run db:migrate",
"test": "jest",
"posttest": "rm test.db"
},
"author": "Alex Phillips <ahp118@gmail.com>",
"license": "ISC",
@ -19,5 +22,9 @@
"passport-jwt": "^4.0.0",
"sequelize": "^5.21.4",
"sqlite3": "^4.1.1"
},
"devDependencies": {
"jest": "^25.1.0",
"sequelize-cli": "^5.5.1"
}
}

36
tests/user.test.js Normal file
View File

@ -0,0 +1,36 @@
const {User} = require('../models/index')
test('Creates a user', async () => {
await User.create({
username: 'admin',
email: 'admin@example.com',
password: 'admin',
});
expect((await User.findAll()).length).toBe(1)
})
test('Password check', async () => {
const user = await User.findOne({
where: {
email: 'admin@example.com'
}
})
expect(user.verifyPassword('admin')).toBe(true)
expect(user.verifyPassword('wrong')).toBe(false)
})
test('Uniqueness of email', async () => {
try {
await User.create({
username: 'test',
email: 'admin@example.com',
password: 'test'
})
} catch (e) {
// Exception means user was unable to be created
}
expect((await User.findAll()).length).toBe(1)
})