Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed "${TEST_INDEX} is initialized to 'null' for video recording path pattern" (close #3455) #3481

Merged
merged 9 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/configuration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import renderTemplate from '../utils/render-template';
import prepareReporters from '../utils/prepare-reporters';
import WARNING_MESSAGES from '../notifications/warning-message';
import log from '../cli/log';
import getConcatenatedValuesString from '../utils/get-concatenated-values-string';

import {
DEFAULT_TIMEOUT,
Expand Down Expand Up @@ -227,7 +228,7 @@ export default class Configuration {
if (!this._overridenOptions.length)
return;

const optionsStr = this._overridenOptions.map(option => `"${option}"`).join(', ');
const optionsStr = getConcatenatedValuesString(this._overridenOptions);
const optionsSuffix = this._overridenOptions.length > 1 ? 's' : '';

Configuration._showConsoleWarning(renderTemplate(WARNING_MESSAGES.configOptionsWereOverriden, optionsStr, optionsSuffix));
Expand Down
7 changes: 6 additions & 1 deletion src/notifications/warning-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,10 @@ export default {

cannotFindConfigurationFile: 'Unable to find the "{path}" configuration file. Error details:\n' +
'\n' +
'{err}'
'{err}',

problematicPathPatternPlaceholderForVideoRecording: '{placeholderList} path pattern placeholder{suffix} {verb} not suitable for the video recording\'s "pathPattern" option.\n' +
'\n' +
'{pronoun} value{suffix} will be replaced with an empty string.'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dirk's version:

    problematicPathPatternPlaceholderForVideoRecording: 'The {placeholderList} path pattern placeholder{suffix} cannot be applied to the recorded video.\n' +
                                                        '\n' +
                                                        'The placeholder{suffix} {verb} replaced with an empty string.'

where {suffix} is s and {verb} is either was or were.

};

2 changes: 1 addition & 1 deletion src/runner/task.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export default class Task extends AsyncEventEmitter {
_createVideoRecorders (browserJobs) {
const videoOptions = { timeStamp: this.timeStamp, ...this.opts.videoOptions };

return browserJobs.map(browserJob => new VideoRecorder(browserJob, this.opts.videoPath, videoOptions, this.opts.videoEncodingOptions));
return browserJobs.map(browserJob => new VideoRecorder(browserJob, this.opts.videoPath, videoOptions, this.opts.videoEncodingOptions, this.warningLog));
}

// API
Expand Down
3 changes: 3 additions & 0 deletions src/utils/get-concatenated-values-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function (array) {
return array.map(item => `"${item}"`).join(', ');
}
27 changes: 22 additions & 5 deletions src/utils/path-pattern.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { escapeRegExp as escapeRe } from 'lodash';
import correctFilePath from '../utils/correct-file-path';
import escapeUserAgent from '../utils/escape-user-agent';
import EventEmitter from 'events';

const DATE_FORMAT = 'YYYY-MM-DD';
const TIME_FORMAT = 'HH-mm-ss';

const ERRORS_FOLDER = 'errors';

const PROBLEMATIC_PLACEHOLDER_VALUE = '';

const PLACEHOLDERS = {
DATE: '${DATE}',
TIME: '${TIME}',
Expand All @@ -30,8 +33,10 @@ const DEFAULT_PATH_PATTERN_FOR_REPORT = `${PLACEHOLDERS.DATE}_${PLACEHOLDERS.TIM
const TEST_ID_TEMPLATE = data => data.testIndex ? `test-${data.testIndex}` : '';
const RUN_ID_TEMPLATE = data => data.quarantineAttempt ? `run-${data.quarantineAttempt}` : '';

export default class PathPattern {
export default class PathPattern extends EventEmitter {
constructor (pattern, fileExtension, data) {
super();

this.pattern = this._ensurePattern(pattern);
this.data = this._addDefaultFields(data);
this.placeholderToDataMap = this._createPlaceholderToDataMap();
Expand Down Expand Up @@ -77,8 +82,9 @@ export default class PathPattern {
};
}

static _buildPath (pattern, placeholderToDataMap, forError) {
let resultFilePath = pattern;
_buildPath (pattern, placeholderToDataMap, forError) {
let resultFilePath = pattern;
const problematicPlaceholders = [];

for (const placeholder in placeholderToDataMap) {
const findPlaceholderRegExp = new RegExp(escapeRe(placeholder), 'g');
Expand All @@ -100,15 +106,26 @@ export default class PathPattern {
return escapeUserAgent(userAgent);
}

return placeholderToDataMap[placeholder];
let calculatedValue = placeholderToDataMap[placeholder];

if (calculatedValue === null || calculatedValue === void 0) {
problematicPlaceholders.push(placeholder);

calculatedValue = PROBLEMATIC_PLACEHOLDER_VALUE;
}

return calculatedValue;
});
}

if (problematicPlaceholders.length)
this.emit('problematic-placeholders-found', { placeholders: problematicPlaceholders });

return resultFilePath;
}

getPath (forError) {
const path = PathPattern._buildPath(this.pattern, this.placeholderToDataMap, forError);
const path = this._buildPath(this.pattern, this.placeholderToDataMap, forError);

return correctFilePath(path, this.fileExtension);
}
Expand Down
21 changes: 17 additions & 4 deletions src/video-recorder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import VideoRecorderProcess from './process';
import TempDirectory from '../utils/temp-directory';
import PathPattern from '../utils/path-pattern';
import WARNING_MESSAGES from '../notifications/warning-message';

import getConcatenatedValuesString from '../utils/get-concatenated-values-string';

const DEBUG_LOGGER = debug('testcafe:video-recorder');

Expand All @@ -21,7 +21,7 @@ const TEMP_MERGE_CONFIG_FILE_PREFIX = 'config';
const TEMP_MERGE_CONFIG_FILE_EXTENSION = 'txt';

export default class VideoRecorder {
constructor (browserJob, basePath, opts, encodingOpts) {
constructor (browserJob, basePath, opts, encodingOpts, warningLog) {
this.browserJob = browserJob;
this.basePath = basePath;
this.failedOnly = opts.failedOnly;
Expand All @@ -31,6 +31,8 @@ export default class VideoRecorder {
this.timeStamp = opts.timeStamp;
this.encodingOptions = encodingOpts;

this.warningLog = warningLog;

this.tempDirectory = new TempDirectory(TEMP_DIR_PREFIX);
this.tempVideoPath = '';
this.tempMergeConfigPath = '';
Expand Down Expand Up @@ -63,6 +65,15 @@ export default class VideoRecorder {
browserJob.on('test-run-before-done', this._createSafeListener(this._onTestRunBeforeDone));
}

_addProblematicPlaceholdersWarning (placeholders) {
const problematicPlaceholderListStr = getConcatenatedValuesString(placeholders);
const suffix = placeholders.length > 1 ? 's' : '';
const verb = placeholders.length > 1 ? 'are' : 'is';
const pronoun = placeholders.length > 1 ? 'Their' : 'Its';

this.warningLog.addWarning(WARNING_MESSAGES.problematicPathPatternPlaceholderForVideoRecording, problematicPlaceholderListStr, suffix, verb, pronoun, suffix);
}

_getTargetVideoPath (testRunInfo) {
const { test, index, testRun } = testRunInfo;

Expand All @@ -72,11 +83,13 @@ export default class VideoRecorder {
testIndex: this.singleFile ? null : index,
quarantineAttempt: null,
now: this.timeStamp,
fixture: this.singleFile ? '' : test.fixture.name,
test: this.singleFile ? '' : test.name,
fixture: this.singleFile ? null : test.fixture.name,
test: this.singleFile ? null : test.name,
parsedUserAgent: connection.browserInfo.parsedUserAgent,
});

pathPattern.on('problematic-placeholders-found', ({ placeholders }) => this._addProblematicPlaceholdersWarning(placeholders));

return join(this.basePath, pathPattern.getPath());
}

Expand Down
18 changes: 18 additions & 0 deletions test/functional/fixtures/video-recording/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,23 @@ if (config.useLocalBrowsers) {
expect(videoFiles.length).to.equal(2);
});
});

it('Should display the warning if there is the not suitable placeholder for the "pathPattern" option was specified', () => {
return runTests('./testcafe-fixtures/index-test.js', '', {
only: 'chrome',
shouldFail: true,
setVideoPath: true,

videoOptions: {
singleFile: true,
pathPattern: '${TEST_INDEX}_.mp4'
}
})
.catch(() => {
expect(testReport.warnings).eql(['"${TEST_INDEX}" path pattern placeholder is not suitable for the video recording\'s "pathPattern" option.' +
'\n\n' +
'Its value will be replaced with an empty string.']);
});
});
});
}
6 changes: 6 additions & 0 deletions test/server/util-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const getCommonPath = require('../../lib/utils/get-common-pat
const resolvePathRelativelyCwd = require('../../lib/utils/resolve-path-relatively-cwd');
const getFilterFn = require('../../lib/utils/get-filter-fn');
const prepareReporters = require('../../lib/utils/prepare-reporters');
const getConcatenatedValuesString = require('../../lib/utils/get-concatenated-values-string');

describe('Utils', () => {
it('Correct File Path', () => {
Expand Down Expand Up @@ -168,6 +169,11 @@ describe('Utils', () => {
expect(getFilterFn({ fixture: 'test' })).to.be.a('function');
});

it('Get concatenated values string', () => {
expect(getConcatenatedValuesString(['param_1'])).eql('"param_1"');
expect(getConcatenatedValuesString(['param_1', 'param_2', 'param_3'])).eql('"param_1", "param_2", "param_3"');
});

describe('Moment Module Loader', () => {
const moduleCacheDesciptor = Object.getOwnPropertyDescriptor(Module, '_cache');
const originalLoad = Module._load;
Expand Down
25 changes: 23 additions & 2 deletions test/server/video-recorder-test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const expect = require('chai').expect;
const { expect } = require('chai');
const VideoRecorder = require('../../lib/video-recorder');
const AsyncEmitter = require('../../lib/utils/async-event-emitter');

const WarningLog = require('../../lib/notifications/warning-log');

const VIDEOS_BASE_PATH = '__videos__';

Expand All @@ -25,4 +25,25 @@ describe('Video Recorder', () => {
expect(videoRecorder.testRunInfo).to.be.empty;
});
});

it('Should correctly format the warning message about no suitable path pattern placeholders', () => {
const browserJobMock = new AsyncEmitter();
const warningLog = new WarningLog();
const videoRecorder = new VideoRecorder(browserJobMock, VIDEOS_BASE_PATH, {}, {}, warningLog);

videoRecorder._addProblematicPlaceholdersWarning(['${TEST_INDEX}']);
expect(warningLog.messages).eql([
'"${TEST_INDEX}" path pattern placeholder is not suitable for the video recording\'s "pathPattern" option.' +
'\n\n' +
'Its value will be replaced with an empty string.'
]);
warningLog.messages = [];

videoRecorder._addProblematicPlaceholdersWarning(['${TEST_INDEX}', '${FIXTURE}']);
expect(warningLog.messages).eql([
'"${TEST_INDEX}", "${FIXTURE}" path pattern placeholders are not suitable for the video recording\'s "pathPattern" option.' +
'\n\n' +
'Their values will be replaced with an empty string.'
]);
});
});