Skip to content

Commit

Permalink
Refactor session-token.spec.js to be an e2e test.
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuester committed Oct 9, 2024
1 parent ecfec46 commit b64060c
Show file tree
Hide file tree
Showing 8 changed files with 142 additions and 198 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ jobs:
node-version: ${{ matrix.node-version }}
- name: Install pyxform
run: pip install git+https://github.com/medic/[email protected]#egg=pyxform-medic
- name: npm ci and test
run: npm ci && npm test
- run: npm ci
- run: npm run eslint
- run: npm test
- name: Archive Results
uses: actions/upload-artifact@v4
with:
Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
"scripts": {
"clean": "rm -rf ./build/",
"eslint": "eslint 'src/**/*.js' test/*.js 'test/**/*.js'",
"docker-start-couchdb": "npm run docker-stop-couchdb && docker run -d -p 6984:5984 --rm --name cht-conf-couchdb couchdb:2.3.1 && sh test/scripts/wait_for_response_code.sh 6984 200 CouchDB",
"docker-stop-couchdb": "docker stop cht-conf-couchdb || true",
"test": "npm run eslint && npm run docker-start-couchdb && npm run clean && mkdir -p build/test && cp -r test/data build/test/data && cd build/test && nyc --reporter=html mocha --forbid-only \"../../test/**/*.spec.js\" --exclude \"../../test/e2e/**/*.spec.js\" && cd ../.. && npm run docker-stop-couchdb",
"test": "npm run clean && mkdir -p build/test && cp -r test/data build/test/data && cd build/test && nyc --reporter=html mocha \"../../test/**/*.spec.js\" --exclude \"../../test/e2e/**/*.spec.js\"",
"test-e2e": "mocha --config test/e2e/.mocharc.js",
"semantic-release": "semantic-release"
},
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/.mocharc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const chaiAsPromised = require('chai-as-promised');
const chai = require('chai');
chai.use(chaiAsPromised);

module.exports = {
allowUncaught: false,
color: true,
Expand Down
48 changes: 29 additions & 19 deletions test/e2e/cht-conf-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,43 @@ const fs = require('fs');
const fse = require('fs-extra');

const log = require('../../src/lib/log');
const { getProjectUrl } = require('./cht-docker-utils');
const { getProjectUrl, DEFAULT_PROJECT_NAME } = require('./cht-docker-utils');

const getProjectDirectory = (projectName) => path.resolve(__dirname, `../../build/${projectName}`);
const getProjectDirectory = (projectName = DEFAULT_PROJECT_NAME) => path.resolve(__dirname, `../../build/${projectName}`);

const runChtConf = (projectName, command) => new Promise((resolve, reject) => {
getProjectUrl(projectName).then(url => {
const projectDirectory = getProjectDirectory(projectName);
const cliPath = path.join(__dirname, '../../src/bin/index.js');
exec(`node ${cliPath} --url=${url} ${command}`, { cwd: projectDirectory }, (error, stdout, stderr) => {
if (!error) {
return resolve(stdout);
}
const runChtConf = async (
command,
{ url, sessionToken } = {},
projectName = DEFAULT_PROJECT_NAME
) => {
const instanceUrl = url || await getProjectUrl(projectName);
const sessionParam = sessionToken ? `--session-token=${sessionToken}` : '';
const projectDirectory = getProjectDirectory(projectName);
const cliPath = path.join(__dirname, '../../src/bin/index.js');
return new Promise((resolve, reject) => {
exec(
`node ${cliPath} --url=${instanceUrl} ${sessionParam} ${command}`,
{ cwd: projectDirectory },
(error, stdout, stderr) => {
if (!error) {
return resolve(stdout);
}

log.error(stderr);
reject(new Error(stdout.toString('utf8')));
});
log.error(stderr);
reject(new Error(stdout.toString('utf8')));
}
);
});
});
};

const cleanupProject = (projectName) => {
const cleanupProject = (projectName = DEFAULT_PROJECT_NAME) => {
const projectDirectory = getProjectDirectory(projectName);
if (fs.existsSync(projectDirectory)) {
fse.removeSync(projectDirectory);
}
};

const initProject = async (projectName) => {
const initProject = async (projectName = DEFAULT_PROJECT_NAME) => {
const projectDirectory = getProjectDirectory(projectName);
cleanupProject(projectName);

Expand All @@ -46,10 +56,10 @@ const initProject = async (projectName) => {
}, null, 4),
);

await runChtConf(projectName, 'initialise-project-layout');
await runChtConf('initialise-project-layout', projectName);
};

const writeBaseAppSettings = async (projectName, baseSettings) => {
const writeBaseAppSettings = async (baseSettings, projectName = DEFAULT_PROJECT_NAME) => {
const projectDirectory = getProjectDirectory(projectName);

return await fs.promises.writeFile(
Expand All @@ -58,7 +68,7 @@ const writeBaseAppSettings = async (projectName, baseSettings) => {
);
};

const readCompiledAppSettings = async (projectName) => {
const readCompiledAppSettings = async (projectName = DEFAULT_PROJECT_NAME) => {
const projectDirectory = getProjectDirectory(projectName);

return JSON.parse(
Expand Down
22 changes: 8 additions & 14 deletions test/e2e/edit-app-settings.spec.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { expect } = require('chai');
const request = require('request-promise-native');

const { DEFAULT_PROJECT_NAME, getProjectUrl } = require('./cht-docker-utils');
const { getProjectUrl } = require('./cht-docker-utils');
const {
cleanupProject,
initProject,
Expand All @@ -11,19 +11,13 @@ const {
} = require('./cht-conf-utils');

describe('edit-app-settings', () => {
const projectName = DEFAULT_PROJECT_NAME;
const findLanguage = (settingsLanguages, locale) => settingsLanguages.find(language => language.locale === locale);

before(async () => {
await initProject(projectName);
});

after(async () => {
await cleanupProject(projectName);
});
before(initProject);
after(cleanupProject);

it('disables a language, recompile, and push app settings', async () => {
const url = await getProjectUrl(projectName);
const url = await getProjectUrl();
const baseSettings = await request.get({ url: `${url}/api/v1/settings`, json: true });
expect(findLanguage(baseSettings.languages, 'en').enabled).to.be.true;
expect(findLanguage(baseSettings.languages, 'fr').enabled).to.be.true;
Expand All @@ -39,18 +33,18 @@ describe('edit-app-settings', () => {
});
baseSettings.locale = 'fr';
baseSettings.locale_outgoing = 'fr';
await writeBaseAppSettings(projectName, baseSettings);
await writeBaseAppSettings(baseSettings);

await runChtConf(projectName, 'compile-app-settings');
const compiledSettings = await readCompiledAppSettings(projectName);
await runChtConf('compile-app-settings');
const compiledSettings = await readCompiledAppSettings();
expect(compiledSettings.languages.find(language => language.locale === 'en')).to.deep.equal({
locale: 'en',
enabled: false,
});
expect(compiledSettings.locale).to.equal('fr');
expect(compiledSettings.locale_outgoing).to.equal('fr');

await runChtConf(projectName, 'upload-app-settings');
await runChtConf('upload-app-settings');
const newSettings = await request.get({ url: `${url}/api/v1/settings`, json: true });
expect(newSettings.languages.find(language => language.locale === 'en')).to.deep.equal({
locale: 'en',
Expand Down
97 changes: 97 additions & 0 deletions test/e2e/session-token.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const { expect } = require('chai');
const rpn = require('request-promise-native');
const fs = require('fs-extra');
const path = require('path');
const PouchDB = require('pouchdb-core');
const { getProjectUrl } = require('./cht-docker-utils');
const {
cleanupProject,
initProject,
getProjectDirectory, runChtConf,
} = require('./cht-conf-utils');

const COUCH_URL_PATTERN = /^(https?:\/\/)([^:]+):([^@]+)@(.*)$/;

const projectPath = getProjectDirectory();

const createProjectPath = async () => {
await initProject();

const docs = [
{ _id: 'one', name: 'Document One' },
{ _id: 'two', name: 'Document Two' },
];

const jsonDocsPath = `${projectPath}/json_docs`;
fs.ensureDirSync(`${projectPath}/json_docs`);

docs.forEach(doc => {
fs.writeJsonSync(path.join(jsonDocsPath, `${doc._id}.doc.json`), doc);
});
};

describe('integration/session-token', () => {
let authenticatedUrl;
let unauthenticatedUrl;
let sessionToken;
const action = 'upload-docs --force';

const initializeDatabase = () => {
PouchDB.plugin(require('pouchdb-adapter-http'));
PouchDB.plugin(require('pouchdb-mapreduce'));
};

const getSessionToken = async (name, password) => {
const options = {
method: 'POST',
uri: `${unauthenticatedUrl}/_session`,
body: {
name,
password,
},
resolveWithFullResponse: true,
json: true
};

try {
const response = await rpn(options);
const setCookieHeader = response.headers['set-cookie'];
// Extract the session token from the set-cookie header
const sessionCookie = setCookieHeader.find(cookie => cookie.startsWith('AuthSession='));
return sessionCookie.split(';')[0].split('=')[1];
} catch (error) {
throw new Error(`Failed to get session token: ${error.message}`);
}
};

before(async () => {
await createProjectPath();
initializeDatabase();
authenticatedUrl = await getProjectUrl();
const [, prefix, user, password, rootUrl] = authenticatedUrl.match(COUCH_URL_PATTERN);
unauthenticatedUrl = `${prefix}${rootUrl}`;
sessionToken = await getSessionToken(user, password);
});

after(cleanupProject);

it('should handle authentication with session token', async () => {
const stdout = await runChtConf(action, { url: unauthenticatedUrl, sessionToken });
expect(stdout).to.contain('INFO upload-docs complete.');
});

it('should handle authentication with basic authentication', async () => {
const stdout = await runChtConf(action, { url: authenticatedUrl });
expect(stdout).to.contain('INFO upload-docs complete.');
});

it('should fail with incorrect session token', async () => {
const incorrectToken = 'incorrect-token';
const promiseToExecute = runChtConf(action, { url: unauthenticatedUrl, sessionToken: incorrectToken });
await expect(promiseToExecute)
.to.be.rejected
.and.eventually.have.property('message')
// Bad Request: Malformed AuthSession cookie
.that.contains('INFO Error: Received error code 400');
});
});
Loading

0 comments on commit b64060c

Please sign in to comment.