diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 60de812..93bd2f9 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -8,6 +8,12 @@ jobs: test: runs-on: ubuntu-latest + env: + MIGRATIONS_DIR: __test-migrations__ + CTF_SPACE_ID: ${{ secrets.CTF_SPACE_ID }} + CTF_ENVIRONMENT_ID: ${{ secrets.CTF_ENVIRONMENT_ID }} + CTF_CMA_TOKEN: ${{ secrets.CTF_CMA_TOKEN }} + steps: - name: Check out code uses: actions/checkout@v2 @@ -25,8 +31,3 @@ jobs: - name: Run tests run: npm test - env: - MIGRATIONS_DIR: __test-migrations__ - CTF_SPACE_ID: TEST_SPACE_ID - CTF_ENVIRONMENT_ID: master - CTF_CMA_TOKEN: dummy_token diff --git a/__test-utils__/create-migration.js b/__test-utils__/create-migration.js index b606adb..cb6f42d 100644 --- a/__test-utils__/create-migration.js +++ b/__test-utils__/create-migration.js @@ -4,13 +4,13 @@ const fs = require('fs') module.exports.createSimpleMigrationFile = () => { const content = ` module.exports.up = (migration, context) => { - const populationCategories = migration + const testContentType = migration .createContentType('testContentType') .name('Test content type') .description('') .displayField('testContentId') - populationCategories + testContentType .createField('testContentId') .name('test content id') .type('Symbol') diff --git a/__test-utils__/log.js b/__test-utils__/log.js deleted file mode 100644 index 51db462..0000000 --- a/__test-utils__/log.js +++ /dev/null @@ -1,10 +0,0 @@ -//utility to get all console log messages in a test context -module.exports.extractLogLinesFromConsole = () => { - const originalLog = console.log - const allLogMessages = [] - console.log = (...args) => { - allLogMessages.push(args.toString()) - originalLog(...args) //print to default console - } - return allLogMessages -} diff --git a/__tests__/generate.test.js b/__tests__/generate.test.js index e1e4034..93590a9 100644 --- a/__tests__/generate.test.js +++ b/__tests__/generate.test.js @@ -1,18 +1,17 @@ const fs = require('fs') const { join } = require('path') const { handler: generateCommand } = require('../bin/commands/generate') -const { extractLogLinesFromConsole } = require('../__test-utils__/log') describe('generate', () => { it('should create a new migration file', async () => { - const stdout = extractLogLinesFromConsole() + //const stdout = extractLogLinesFromConsole() const migrationName = 'test-migration' - await generateCommand({ name: migrationName }) + let result = await generateCommand({ name: migrationName }) let numberOfMigrationsInMigrationsDir = fs.readdirSync(process.env.MIGRATIONS_DIR).length expect(numberOfMigrationsInMigrationsDir).toBe(1) - const migrationFileName = stdout[0].split(' ').find((m) => m.indexOf('js') > -1) + const migrationFileName = result.split(' ').find((m) => m.indexOf('js') > -1) const migrationFilePath = `${process.env.MIGRATIONS_DIR}/${migrationFileName}` const migrationFile = fs.readFileSync(migrationFilePath, 'utf-8') const template = fs.readFileSync(join(__dirname, '..', 'templates', 'migration.mustache'), 'utf8') diff --git a/__tests__/integrations/README.md b/__tests__/integrations/README.md new file mode 100644 index 0000000..123dfef --- /dev/null +++ b/__tests__/integrations/README.md @@ -0,0 +1,24 @@ +# Integration tests + +These tests are meant to test the integrations to contentful. +The purpose of these tests are to run the code towards a real contentful space. + +## Setup + +There are two ways to enable integration tests. +The safest option is to create a new contentful space dedicated to running the tests. +The other option is to run the tests against an existing contentful space but with an environment dedicated to running the tests. + + +1. Create a contentful space +2. Add env variables to `.env.test` file + 1. `CONTENTFUL_SPACE_ID` - the id of the contentful space + 2. `CTF_ENVIRONMENT_ID` - the environment to run the tests in + 3. `CTF_CMA_TOKEN` - the access token for the contentful space + +## Usage + +1. There are 2 utility functions that needs be used before running the tests. + 1. `setupTestContentfulSpace` - creates a contentful space + 2. `resetTestContentfulSpace` - deletes a contentful space +2. Run `npm run test:integration` to run the tests -- CHECK THIS \ No newline at end of file diff --git a/__tests__/integrations/migrate.test.js b/__tests__/integrations/migrate.test.js new file mode 100644 index 0000000..34bf4e6 --- /dev/null +++ b/__tests__/integrations/migrate.test.js @@ -0,0 +1,23 @@ +const { handler: migrateCommand } = require('../../bin/commands/migrate') +const { handler: rollbackCommand } = require('../../bin/commands/rollback') +const { createSimpleMigrationFile } = require('../../__test-utils__/create-migration') + +afterEach(async () => { + //unapply the migration done by the tests + await rollbackCommand({ force: true }) +}) + +describe('migrate', () => { + test('migrate if the force flag is used against master', async () => { + createSimpleMigrationFile() + + let result = await migrateCommand({ force: true }) + + expect(result).toBe('Applied the following migrations:\n 20230609122547608 - new-migration') + }, 100000) + + test('log if there are no migrations to apply', async () => { + let result = await migrateCommand({ force: true }) + expect(result).toBe('No migrations to apply.') + }, 100000) +}) diff --git a/__tests__/list.test.js b/__tests__/list.test.js index d83751a..9e47af4 100644 --- a/__tests__/list.test.js +++ b/__tests__/list.test.js @@ -1,6 +1,5 @@ const { setupMockedContentfulApi, closeMockedContentfulApi } = require('../mocks/contentful/baseContentfulHandler') const { handler: listCommand } = require('../bin/commands/list') -const { extractLogLinesFromConsole } = require('../__test-utils__/log') const { listOneMigrationAppliedHandler } = require('../mocks/contentful/handlers/list/oneAppliedMigrationsHandler') const { listNoAppliedMigrationHandler } = require('../mocks/contentful/handlers/list/noAppliedMigrationsHandler') const { createSimpleMigrationFile } = require('../__test-utils__/create-migration') @@ -12,9 +11,8 @@ describe('list', () => { let numberOfMigrationsInMigrationsDir = readdirSync(process.env.MIGRATIONS_DIR).length expect(numberOfMigrationsInMigrationsDir).toBe(0) - const stdout = extractLogLinesFromConsole() - await listCommand() - expect(stdout).toContain('Found no applied migrations') + let result = await listCommand() + expect(result).toBe('Found no applied migrations') closeMockedContentfulApi() }) @@ -25,10 +23,11 @@ describe('list', () => { let numberOfMigrationsInMigrationsDir = readdirSync(process.env.MIGRATIONS_DIR).length expect(numberOfMigrationsInMigrationsDir).toBe(1) - const stdout = extractLogLinesFromConsole() - await listCommand() - expect(stdout).toContain('Applied migrations:') - expect(stdout).toContain('20230609122547608 - new-migration') + //todo: fix + let result = await listCommand() + expect(result).toBe('Applied migrations:\n 20230609122547608 - new-migration') + /*expect(stdout).toContain('Applied migrations:') + expect(stdout).toContain('20230609122547608 - new-migration')*/ closeMockedContentfulApi() }) }) diff --git a/__tests__/migrate.test.js b/__tests__/migrate.test.js index be8dbe3..0ff23cc 100644 --- a/__tests__/migrate.test.js +++ b/__tests__/migrate.test.js @@ -1,13 +1,11 @@ const { handler: migrateCommand } = require('../bin/commands/migrate') -const { extractLogLinesFromConsole } = require('../__test-utils__/log') const { setupMockedContentfulApi, closeMockedContentfulApi } = require('../mocks/contentful/baseContentfulHandler') describe('migrate', () => { it('should demand user to use "--force" flag if running against master space', async () => { setupMockedContentfulApi() - const stdout = extractLogLinesFromConsole() - await migrateCommand(false) - expect(stdout).toContain('Executing migrations against master requires the --force flag.') + let result = await migrateCommand(false) + expect(result).toBe('Executing migrations against master requires the --force flag.') closeMockedContentfulApi() }) }) diff --git a/__tests__/reset.test.js b/__tests__/reset.test.js index e9dcc3e..f59a4f1 100644 --- a/__tests__/reset.test.js +++ b/__tests__/reset.test.js @@ -1,10 +1,13 @@ const { handler: resetCommand } = require('../bin/commands/reset') -const { extractLogLinesFromConsole } = require('../__test-utils__/log') +const { setupMockedContentfulApi, closeMockedContentfulApi } = require('../mocks/contentful/baseContentfulHandler') +const { listNoAppliedMigrationHandler } = require('../mocks/contentful/handlers/list/noAppliedMigrationsHandler') describe('reset', () => { it('should not reset environment if on master', async () => { - const stdout = extractLogLinesFromConsole() - await resetCommand({ force: false }) - expect(stdout).toContain(`Can't reset environment if you are on master.`) + setupMockedContentfulApi() + + let result = await resetCommand({ force: false }) + expect(result).toBe(`Can't reset environment if you are on master.`) + closeMockedContentfulApi() }) }) diff --git a/__tests__/rollback.test.js b/__tests__/rollback.test.js index 48202b3..8cacd4d 100644 --- a/__tests__/rollback.test.js +++ b/__tests__/rollback.test.js @@ -1,13 +1,15 @@ const fs = require('fs') const { join } = require('path') const { handler: rollbackCommand } = require('../bin/commands/rollback') -const { extractLogLinesFromConsole } = require('../__test-utils__/log') -const { handler: migrateCommand } = require('../bin/commands/migrate') +const { setupMockedContentfulApi, closeMockedContentfulApi } = require('../mocks/contentful/baseContentfulHandler') describe('rollback', () => { it('should demand user to use "--force" flag if running against master space', async () => { - const stdout = extractLogLinesFromConsole() - await rollbackCommand({ force: false }) - expect(stdout).toContain('Executing migrations against master requires the --force flag.') + setupMockedContentfulApi() + + let result = await rollbackCommand({ force: false }) + expect(result).toBe('Executing migrations against master requires the --force flag.') + + closeMockedContentfulApi() }) }) diff --git a/bin/commands/generate.js b/bin/commands/generate.js index 793e6d9..d3a319a 100755 --- a/bin/commands/generate.js +++ b/bin/commands/generate.js @@ -34,7 +34,9 @@ exports.handler = async ({ name }) => { const migrationPath = join(migrationsDir, migrationFileName) await writeFileAsync(migrationPath, migrationContents) - log.success(`Migration file ${migrationFileName} created`) + let successString = `Migration file ${migrationFileName} created` + log.success(successString) + return successString } catch (e) { log.error('Migration file creation failed.', e) process.exitCode = 1 diff --git a/bin/commands/list.js b/bin/commands/list.js index 036e378..96c3c9f 100644 --- a/bin/commands/list.js +++ b/bin/commands/list.js @@ -18,14 +18,13 @@ exports.handler = async () => { const appliedMigrations = await list(space) appliedMigrations.sort((a, b) => b.timestamp.localeCompare(a.timestamp)) if (appliedMigrations.length) { - log.info('Applied migrations:') - console.group() - appliedMigrations.forEach((m) => { - log.info(m) - }) - console.groupEnd() + let appliedMigrationsString = 'Applied migrations:\n ' + appliedMigrations.join('\n ') + log.info('appliedMigrationsString') + return appliedMigrationsString } else { - log.info('Found no applied migrations') + let noAppliedMigrationsString = 'Found no applied migrations' + log.info(noAppliedMigrationsString) + return noAppliedMigrationsString } } catch (e) { log.error(e) diff --git a/bin/commands/migrate.js b/bin/commands/migrate.js index d139f01..54f3348 100755 --- a/bin/commands/migrate.js +++ b/bin/commands/migrate.js @@ -20,13 +20,15 @@ exports.builder = (yargs) => { exports.handler = async ({ force }) => { try { if (env('CTF_ENVIRONMENT_ID') === 'master' && !force) { - log.error('Executing migrations against master requires the --force flag.') - return + let errorString = 'Executing migrations against master requires the --force flag.' + log.error(errorString) + return errorString } - await apply({ rollback: false }) + return await apply({ rollback: false }) } catch (e) { log.error(e) process.exitCode = 1 + return e.toString() } } diff --git a/bin/commands/reset.js b/bin/commands/reset.js index 63b63f4..51a6ca4 100644 --- a/bin/commands/reset.js +++ b/bin/commands/reset.js @@ -12,8 +12,9 @@ exports.desc = 'Resets current CTF_ENVIRONMENT_ID to master.' exports.handler = async () => { try { if (env('CTF_ENVIRONMENT_ID') === 'master') { - log.error(`Can't reset environment if you are on master.`) - return + let errorString = `Can't reset environment if you are on master.` + log.error(errorString) + return errorString } const space = await spaceModule(env('CTF_SPACE_ID'), env('CTF_ENVIRONMENT_ID'), env('CTF_CMA_TOKEN')) diff --git a/bin/commands/rollback.js b/bin/commands/rollback.js index 05289fd..6621d4b 100644 --- a/bin/commands/rollback.js +++ b/bin/commands/rollback.js @@ -6,6 +6,7 @@ const env = require('../../lib/env') const cliSelect = require('cli-select') const spaceModule = require('../../lib/contentful-space-manager') const log = require('../../lib/log') +const { error } = require('../../lib/log') exports.command = 'rollback' @@ -28,8 +29,9 @@ exports.builder = (yargs) => { exports.handler = async ({ force, interactive }) => { try { if (env('CTF_ENVIRONMENT_ID') === 'master' && !force) { - log.error('Executing migrations against master requires the --force flag.') - return + let errorString = 'Executing migrations against master requires the --force flag.' + log.error(errorString) + return errorString } if (interactive) { diff --git a/jest.setupFiles.js b/jest.setupFiles.js index 9485304..2255c6b 100644 --- a/jest.setupFiles.js +++ b/jest.setupFiles.js @@ -1,14 +1,2 @@ const dotenv = require('dotenv') dotenv.config({ path: './.env.test' }) - -//mock lib/log since encoding characters from chalk makes testing difficult -jest.mock('./lib/log', () => { - console.log('Setting up mocked log') - return { - _esModule: false, - info: (...message) => console.log(...message), - success: (...message) => console.log(...message), - error: (...message) => console.log(...message), - warn: (...message) => console.log(...message), - } -}) diff --git a/mocks/contentful/baseContentfulHandler.js b/mocks/contentful/baseContentfulHandler.js index 71338e9..6d47fc4 100644 --- a/mocks/contentful/baseContentfulHandler.js +++ b/mocks/contentful/baseContentfulHandler.js @@ -7,6 +7,10 @@ let mockedContentfulServer = null module.exports.baseURL = 'https://api.contentful.com/spaces/TEST_SPACE_ID' module.exports.setupMockedContentfulApi = (handlers) => { + //set up environment variables to match mocked responses from contentful + process.env['CTF_SPACE_ID'] = 'TEST_SPACE_ID' + process.env['CTF_ENVIRONMENT_ID'] = 'master' + if (handlers == null) { handlers = [] } diff --git a/src/migrator.js b/src/migrator.js index 06609a8..d2134f5 100644 --- a/src/migrator.js +++ b/src/migrator.js @@ -132,6 +132,15 @@ const migrate = async (space, options = {}) => { await runMigrations(migrationsToApply, space.env.sys.id) await updateBookkeeping(space, migrationsToApply, options) log.info(options.rollback ? 'Rolled back.' : 'Migrated.') + + let successString + if (options.rollback) { + successString = 'Successful rollback of the following migrations:\n ' + migrationsToApply.join('\n ') + } else { + successString = 'Applied the following migrations:\n ' + migrationsToApply.join('\n ') + } + log.info(successString) + return successString } const delay = (time) => new Promise((resolve) => setTimeout(resolve, time)) @@ -185,8 +194,9 @@ const apply = async (options = {}) => { const migrationsToHandle = await getMigrationsToHandle(space, options) if (!migrationsToHandle.length) { - log.info(`No migrations to ${options.rollback ? 'rollback' : 'apply'}.`) - return + let noMigrationsMessage = `No migrations to ${options.rollback ? 'rollback' : 'apply'}.` + log.info(noMigrationsMessage) + return noMigrationsMessage } if (options.rollback) { @@ -195,22 +205,24 @@ const apply = async (options = {}) => { log.info('About to apply the following migrations:\n ' + migrationsToHandle.join('\n ')) } + //todo: depending on env the way to migrate differ? if (env('CTF_ENVIRONMENT_ID') === 'master') { const newEnvId = utcTimestamp({ dashes: true }) - + let result try { await failIfNoAvailableEnvironments(space) const spaceNewEnv = await createEnv(space, newEnvId) - await migrate(spaceNewEnv, options) + result = await migrate(spaceNewEnv, options) + await switchEnvAliasAndDropOldEnv(space, newEnvId) - return + return result } catch (e) { await space.deleteSpaceEnv(newEnvId) throw e } } - await migrate(space, options) + return await migrate(space, options) } const create = async ({ newEnvId }) => {