Я работаю над реализацией теста, который читает список файлов из заданного каталога. Затем список сверяется с объектом Map
, который использует имена файлов в качестве ключей. Если совпадение найдено, я хочу выполнить некоторые тесты, если нет, пропустить файл и перейти к следующему.
У меня работает тест, если я просто беру один объект с карты, но он терпит неудачу, когда я пытаюсь зациклиться. Я хочу запускать тесты, перебирая несколько файлов.
Это кажется проблемой только в том случае, если в моих тестах есть асинхронные вызовы. Используя полностью синхронный цикл, я могу заставить его работать нормально. Вот пример синхронного цикла (Я понимаю, что это очень надуманный пример, но он работает так, как ожидалось):
describe('a test', () => {
const list = ['a', 'b', 'c'];
const test = (x) => {
describe(`should run ${x}`, () => {
beforeAll(async () => {
console.info('beforeAll');
});
beforeEach(async () => {
console.info('beforeEach');
});
for(let i = 0; i < 2; i++) {
it(`should log iteration ${i}`, async () => {
console.info(x, i);
expect(i).toBeTruthy();
});
}
});
}
for (let i = 0; i < list.length; i++) {
test(list[i]);
}
});
Вывод из приведенного выше фрагмента говорит о том, что он работает нормально:
Однако этот же шаблон не работает, если он асинхронный. На самом деле, насколько я могу судить, вложенное описание в test
даже не работает. Я записал переменную project
в консоль, чтобы видеть, что она вызывается, но оператор logging in...
в beforeAll
вообще не выполняется. Кажется, что он просто пропускает прямо через него. Как мне заставить это работать с async/await
?
describe('Import Project', () => {
const _page = new PageFactory();
const utils = new Utils();
const projPath = browser.params.projPath;
let projectGuid: string;
const test = (project) => {
describe(`importing ${project.name}`, () => {
beforeAll(async () => {
console.info('logging in...'); //not getting executed for some reason
await _page.loginPage.login(browser.params.username, browser.params.password);
// import
await _page.projectsPage.importProject(projectPath + project.filename)
.withImportType(project.importType)
.withProjectName(project.projectName)
.inEnvironment(project.environment)
.import();
projectGuid = await utils.extractGuid();
});
afterEach(async () => {
await _page.designerPage.navigateTo(projectGuid);
});
for(let i = 0; i < project.operations.length; i++) {
const operation = project.operations[i];
it(`should run ${operation.name} successfully`, async () => {
await runOperation(operation.name);
const status = await _page.operationLogsPage.getStatus(operation.outcomeTarget);
expect(status).toEqual(operation.expectedStatus);
});
}
});
}
utils.getProjects().then(projects => {
// projects is a string[] of filenames
// that are returned using fs.readdir()
for (let i = 0; i < projects.length; i++) {
const myProject = projectMap.get(projects[i]);
if (myProject) {
test(myProject);
}
}
});
});
Результат от этого просто Executed 0 of 0 specs SUCCESS in 0.003 sec.
Я не понимаю, чем это отличается от ручного написания всех этих вложенных блоков описания. Если бы я выписал каждый из них, он бы работал нормально, но по какой-то причине в цикле он не хочет работать. Есть идеи?
цикл for не ожидает внутри себя асинхронной процедуры. это связано с этим вопросом stackoverflow.com/questions/11488014/…
Этот ответ предполагает несколько вещей, которые не работают. .forEach(async p => { // do stuff }
терпит неудачу с тем же результатом. Помещение цикла внутри асинхронной функции, такой как async function something() { for(..) { await test(project) } }
, тоже не работает.
Я не мог понять, как заставить это работать так, как я хотел. Вместо этого я решил использовать узел child_process.execSync
и таким образом перебирал каждый файл. Это не идеально, но это работает. Занимает немного больше времени, так как каждый файл, который я хочу запустить для тестов, создает новый сеанс, но я устал пытаться заставить его работать по-другому.
Я запускаю скрипт, используя node ./path/to/test.js --baseUrl=http://<myUrl>
Вот соответствующая часть кода:
fs.readdir(projectsPath, (err, files) => {
if (err) {
throw new Error('Unable to scan directory: ' + err);
}
let i = 0;
const next = () => {
if (i < files.length) {
const file = files[i];
console.info('running tests on:', file);
const runCmd = `nodenv --exec "yarn run e2e:all ${baseUrl} --params.projectToImport=${file} --suite import_projects"`
// exec
try {
execSync(runCmd, { cwd: workingDir, stdio: 'inherit' },
(error, stdout, stderr) => {
if (error) {
console.error(error);
return;
}
console.info(stdout);
});
} catch (err) {
if (err.stderr) {
console.info('stderr:', err.stderr.toString());
}
}
// next iteration
i++;
next();
}
}
next();
});
Для справки, я также пробовал ждать
test
. Это тоже не сработало.