How to use listTestFiles method in Playwright Internal

Best JavaScript code snippet using playwright-internal

cli.js

Source:cli.js Github

copy

Full Screen

1/* eslint-disable global-require,max-len, no-empty,no-console */2const path = require('path');3const fs = require('fs');4const { Execute } = require('../../core/runner/execute');5const { MochaReportListener, ReportPortalAgent } = require('../../core/report');6const { RunnerHelper, ReportHelper, ConfigHelper, PerformanceHelper } = require('../../core/helper');7const { LoggerListener, Logger } = require('../../core/log');8const { Log4jsConfig } = require('../../core/config/log4js');9const { BuildInfo } = require('../../services/common/build.info.service');1011Log4jsConfig('logs/pre-setup-log');12function notifyMessage() {13 printToConsoleWithRedColor(14 '\nCompleted executing test, please view detail report in 192.168.50.96:8080 or in folder reports!. Execution process will exit after 5s'15 );16 resetConsoleLogColor();17}1819async function finishAllReportAgentRequests(reportAgents, parallel, resolve) {20 {21 if (RunnerHelper.debugMode) return resolve('Completed Run In Debug Mode');22 const completeAllPoolLaunch = [];23 reportAgents.forEach(async (agent) => {24 if (parallel) {25 completeAllPoolLaunch.push(agent.finishAllAgentRequests());26 } else {27 completeAllPoolLaunch.push(finishLaunchInSingleThread(agent));28 }29 });30 return Promise.all(completeAllPoolLaunch).then((result) => {31 console.log('Completed send all log to agent', result);32 resolve();33 });34 }35}3637async function finishLaunchInSingleThread(agent) {38 await agent.finishAllAgentRequests();39 await agent.sendLaunchRequest({}, false, true);40 notifyMessage();41}4243/**44 *45 * username46 * password47 * sftpUser48 * sftpPass49 * alternativeAccounts50 * namespace51 * env52 * @param {Object} argv53 * @example54 * {55 * username: "sampleUser",56 * password: "samplePass",57 * sftpUser: "sampleSftpUser",58 * sftpPass: "sampleSftpPass",59 * namespace: "auto_qa",60 * env: "qa",61 * alternativeAccounts: {admin:adminImpersonateUser/pass, manager:managerImpersonateUser/pass}62 * }63 */64function setUpAuthenticateVariable(argv) {65 const { username, password, sftpUser, sftpPass, alternativeAccounts, namespace, env } = argv;66 ConfigHelper.restAuthenticateUserName = username;67 ConfigHelper.restAuthenticatePassword = password;68 ConfigHelper.sftpAuthenticateUserName = sftpUser;69 ConfigHelper.sftpAuthenticatePassword = sftpPass;70 ConfigHelper.listAuthenticateAccount = alternativeAccounts;71 ConfigHelper.namespace = namespace;72 ConfigHelper.environment = env;73}7475/**76 * restServiceConfig - rest service config file name Ex: local.config.json77 * sftpServiceConfig - sftp service config file name Ex: local.config.json78 * scenarios - folder path contains all test scripts79 * debug - enalbe debug mode80 * appRootPath - root path, this will use to automatically search the config81 * file.82 * Ex:83 * restServiceConfig=sample.local.json84 * appRootPath=D:/API85 * This will automatically search the sample.local.json inside86 * D:/API/config/runner/rest.service/sample.local.json87 * @param {Object} argv88 * @example89 * {90 * restServiceConfig: "qa.config.json",91 * sftpServiceConfig: "edi.config.json",92 * scenarios: "scenarios",93 * debug: false,94 * appRootPath: "D:/API-AUTO"95 * }96 */97function setUpServiceConfigFiles(argv) {98 const { restServiceConfig, sftpServiceConfig, scenarios, debug, appRootPath } = argv;99 RunnerHelper.appRootPath = appRootPath;100 RunnerHelper.debugMode = debug;101 RunnerHelper.testFolderPath = path.join(RunnerHelper.appRootPath, scenarios);102 RunnerHelper.restServiceConfigFilePath = path.join(103 RunnerHelper.appRootPath,104 'config',105 'runner',106 'rest.service',107 restServiceConfig108 );109 RunnerHelper.sftpServiceConfigFilePath = path.join(110 RunnerHelper.appRootPath,111 'config',112 'runner',113 'sftp.service',114 sftpServiceConfig115 );116}117118/**119 * below function will split list test files120 * to multiple thread pool by their naming convention121 * Ex: CON_Sample_1, CON_Sample_2, ADJ_Sample_1, ADJ_Sample_2122 * will create 2 thread pool. The first thread pool will store all test script123 * has CON prefix and the second thread pool will store all test script124 * has ADJ prefix125 * :D this function can be used in feature if our team want126 * to run test in parallel based on their module and avoid having an issue127 * with shared test data in the same module128 * We just replace the method in function createExecutionPool129 * const testFiles = listTestFiles.splice(0, totalFileToSplit);130 * by the new one below131 * const testFiles = listTestFiles.splice(0, splitTestFilesByModuleName(listTestFiles));132 */133function splitTestFilesByModuleName(listTestFiles) {134 const baseFile = listTestFiles[0];135 const baseModuleName = baseFile.split('_')[0];136 const listTestFilesInModule = [];137 for (const testFile of listTestFiles) {138 const moduleName = testFile.split('_')[0];139 if (moduleName === baseModuleName) listTestFilesInModule.push(testFile);140 else break;141 }142 return listTestFilesInModule.length;143}144145let buildInfoDataCache = null;146async function getBuildInfo() {147 if (!buildInfoDataCache) {148 const buildInfo = new BuildInfo();149 buildInfoDataCache = await buildInfo.getBuildInfo();150 }151 return Promise.resolve(buildInfoDataCache);152}153function printToConsoleWithRedColor(message) {154 console.log('\x1b[31m', message);155}156157function resetConsoleLogColor() {158 console.log('\x1b[0m', '\n');159}160161function setUpConfigAndRunTest(argv, appRootPath, reportConfig, completedCallback = () => {}) {162 argv.appRootPath = appRootPath;163 setUpAuthenticateVariable(argv);164 setUpServiceConfigFiles(argv);165 run(argv, appRootPath, reportConfig, completedCallback);166}167168function run(argv, appRootPath, reportConfig, completedCallback = () => {}) {169 const log = new Logger('ExecutionLog');170 const {171 tags,172 timeout,173 reportPortalConfig,174 launchName,175 launchDescription,176 launchTags,177 suiteName,178 suiteDescription,179 suiteTags,180 retries,181 parallel,182 performanceLog183 } = argv;184 // eslint-disable-next-line import/no-dynamic-require185 const ReportPortalConfig = require(path.join(RunnerHelper.appRootPath, 'config', 'report', reportPortalConfig));186 const logListener = new Logger('Listener');187 let countRetries = 0;188 let retriesScripts = [];189190 /**191 * Init ReportPortal Agent and setup Log4JS192 */193 Log4jsConfig(null);194 ReportHelper.reportAgentClass = ReportPortalAgent;195 if (RunnerHelper.debugMode) {196 console.log('Run In Debug Mode');197 startRunTest(Promise.resolve.bind(Promise), Promise.reject.bind(Promise))198 .then((result) => {199 console.log(result);200 })201 .catch((error) => {202 console.log(error);203 });204 } else {205 ReportHelper.createReportAgent(ReportPortalConfig, ReportHelper.defaultReportStoreKey)206 .then(async (agent) => {207 return new Promise(async (resolve, reject) => {208 performanceLog && PerformanceHelper.captureHeapMemory(RunnerHelper.appRootPath, 'StartExecuteTest');209 startRunTest(agent, resolve, reject);210 });211 })212 .then(async () => {213 // Start to run retries failed test214 await performRunRetry();215 await completedCallback();216 ReportHelper.mergeJenkinsResult(RunnerHelper.appRootPath, parallel);217 notifyMessage();218 setTimeout(() => process.exit(0), 5000);219 })220 .catch(async (err) => {221 /**222 * allow executing test event when ReportPortal server shutting down223 */224 log.error('Has error when executing test', err);225 logListener.error('Has error when executing test', err);226 Log4jsConfig(null);227 await handleExecuteException(err);228 });229 }230231 async function startRunTest(agent, resolve, reject) {232 try {233 return invokeTests(resolve);234 } catch (err) {235 return reject(err);236 }237 }238 /**239 *240 * @param {Promise} resolve241 * @param {Boolean} isRetries242 * Execute test243 */244 async function invokeTests(resolve, isRetries = false) {245 try {246 const responseRawInfo = await getBuildInfo();247 log.info('================== START RUN SUITE ======================');248 log.info('=========================================================');249 log.info('Run Test With Options', argv);250 log.info('Build Info:', responseRawInfo);251 retriesScripts = [...ReportHelper.failedTestScripts];252 ReportHelper.clearFailedTestScripts();253 if (isRetries) {254 return executeTestWithRetries(resolve, responseRawInfo);255 }256 const fileOrFolderStats = fs.statSync(RunnerHelper.testFolderPath);257 const isSigleTestFile = fileOrFolderStats.isFile();258 return executeTest(resolve, isSigleTestFile, responseRawInfo);259 } catch (err) {260 log.error(err);261 throw err;262 }263 }264265 async function invokeRunRetries() {266 return new Promise(async (resolve, reject) => {267 try {268 countRetries++;269 return invokeTests(resolve, true);270 } catch (err) {271 return reject(err);272 }273 });274 }275276 /**277 *278 * @param {Promise} resolve279 * @param {Boolean} isSigleTestFile280 * @param {Object} responseRawInfo281 * Create excution context282 */283 async function executeTest(resolve, isSigleTestFile, responseRawInfo) {284 log.info('Execution First Time');285 const reportAgent = RunnerHelper.debugMode ? {} : ReportHelper.getAgent(ReportHelper.defaultReportStoreKey);286 const launchResult = await startLaunch(reportAgent, responseRawInfo.body, false);287 const listTestFiles = isSigleTestFile288 ? [RunnerHelper.testFolderPath]289 : RunnerHelper.filterFileByExtensionAndTag(RunnerHelper.testFolderPath, tags, '.js', []);290 const executionPool = createExecutionPool(listTestFiles, launchResult.id, responseRawInfo, false);291 performanceLog && PerformanceHelper.captureHeapMemory(RunnerHelper.appRootPath, `executeTest${Date.now()}`);292 await executeRun(executionPool, resolve);293 }294295 /**296 *297 * @param {Promise} resolve298 * @param {Array} retriesScripts299 * @param {Object} responseRawInfo300 * Create excution context for re-running failed scripts301 */302 async function executeTestWithRetries(resolve, responseRawInfo) {303 log.info('Execution Failed Tests');304 const reportAgent = RunnerHelper.debugMode ? {} : ReportHelper.getAgent(ReportHelper.defaultReportStoreKey);305 const launchResult = await startLaunch(reportAgent, responseRawInfo.body, true);306 const executionPool = createExecutionPool(retriesScripts, launchResult.id, responseRawInfo, true);307 performanceLog &&308 PerformanceHelper.captureHeapMemory(RunnerHelper.appRootPath, `executeTestWithRetries${Date.now()}`);309 return executeRun(executionPool, resolve);310 }311312 function executeRun(executionPool, resolve) {313 log.info('Start to execute tests');314 return Promise.all(executionPool).then(async (reportAgents) =>315 finishAllReportAgentRequests(reportAgents, parallel, resolve)316 );317 }318319 async function startLaunch(agent, buildInfoData, isRetries) {320 if (RunnerHelper.debugMode) return Promise.resolve(-1);321 const { reportDescription, reportTags } = ReportHelper.reportPortalInfo(buildInfoData);322 const retriesName = `Retries Failed Test ${launchName || ReportPortalConfig.launch} ${countRetries} times`;323 const defaultName = launchName || ReportPortalConfig.launch;324 const name = isRetries ? retriesName : defaultName;325 return agent.sendLaunchRequest(326 {327 name,328 description: `${launchDescription}\n${reportDescription}`,329 tags: launchTags.concat(reportTags)330 },331 true332 );333 }334335 // We create execution pool base on test script module336 // Group all related test script of same module to thread pool337 function createExecutionPool(listTestFiles, launchId, responseRawInfo, isRetries = false) {338 log.info('Create Execution Pool');339 if (!parallel) {340 return [createMultipleExcute(listTestFiles, launchId, responseRawInfo, 1, isRetries)];341 }342 const executionPools = [];343 let currentPoolNumber = 1;344 while (listTestFiles.length > 0) {345 // const testFiles = listTestFiles.splice(0, totalFileToSplit);346 const testFiles = listTestFiles.splice(0, splitTestFilesByModuleName(listTestFiles));347 executionPools.push(createMultipleExcute(testFiles, launchId, responseRawInfo, currentPoolNumber, isRetries));348 currentPoolNumber++;349 }350 return executionPools;351 }352353 function createMultipleExcute(listTestFiles, launchId, responseRawInfo, currentPoolNumber, isRetries = false) {354 log.info('Create Execution Tasks');355 const buildInfoData = responseRawInfo.body;356 const reportStoreKey = listTestFiles.map((file) => path.basename(file)).join('_');357 const reportPath = isRetries ? `reports/retries${countRetries}` : 'reports';358 return new Promise(async (resolve) => {359 createExecutionTask(resolve, listTestFiles, {360 launchId,361 reportPath,362 reportStoreKey,363 currentPoolNumber,364 buildInfoData,365 isRetries366 });367 });368 }369370 function createExecutionTask(resolve, listTestFiles, executionTaskOption) {371 log.info('Create Execution Task');372 if (RunnerHelper.debugMode) return createExecutionTaskDebugMode(resolve, listTestFiles, executionTaskOption);373 return createExecutionTaskWithReportAgent(resolve, listTestFiles, executionTaskOption);374 }375376 function createExecutionTaskDebugMode(resolve, listTestFiles, executionTaskOption) {377 log.info('Create Execution Task Debug Mode');378 const { reportPath, currentPoolNumber, isRetries } = executionTaskOption;379 new Execute({ isRetries })380 .addCompleteCallBack(() => {381 resolve(1);382 })383 .setTimeout(timeout)384 .addReporter(385 'mocha-multi-reporters',386 Object.assign(reportConfig, {387 mochaJenkinsReporterReporterOptions: {388 junit_report_path: `${reportPath}/JUnitResult_${currentPoolNumber}.xml`389 }390 })391 )392 .addTestFiles(listTestFiles)393 .run()394 .addTestListener(new LoggerListener());395 }396397 function createExecutionTaskWithReportAgent(resolve, listTestFiles, executionTaskOption) {398 log.info('Create Execution Task With Report Agent');399 const { launchId, reportPath, reportStoreKey, currentPoolNumber, buildInfoData, isRetries } = executionTaskOption;400 return ReportHelper.createReportAgent(ReportPortalConfig, reportStoreKey).then((reportAgent) => {401 // To avoid having mutliple launch402 // and we need to merge it after run test403 // We will create a default launch and any reportportal agent404 // in executionTask will use it as parent launch405 reportAgent.sendLaunchRequest(406 {407 id: launchId408 },409 true410 );411 new Execute({ isRetries })412 .addCompleteCallBack(() => {413 resolve(reportAgent);414 })415 .setTimeout(timeout)416 .addReporter(417 'mocha-multi-reporters',418 Object.assign(reportConfig, {419 mochaJenkinsReporterReporterOptions: {420 junit_report_path: `${reportPath}/JUnitResult_${currentPoolNumber}.xml`421 }422 })423 )424 .addTestFiles(listTestFiles)425 .run()426 .addTestListener(new LoggerListener())427 .addTestListener(crateMochaReportPortalListener(reportAgent, buildInfoData, true));428 return reportAgent;429 });430 }431 async function performRunRetry() {432 const agent = ReportHelper.getReportPortalAgent(ReportHelper.defaultReportStoreKey);433 const hasFailedScripts = ReportHelper.failedTestScripts.length > 0;434 await agent.finishAllAgentRequests();435 await agent.sendLaunchRequest({}, false, true);436 for (let retriesRun = 1; retriesRun <= retries && hasFailedScripts; retriesRun++) {437 log.debug(`\nRetries failed test ${retriesRun} times`);438 printToConsoleWithRedColor(`Retries failed test ${retriesRun} times`);439 resetConsoleLogColor();440 performanceLog &&441 PerformanceHelper.captureHeapMemory(RunnerHelper.appRootPath, `StartExecuteRetries${retriesRun}`);442 await ReportHelper.clearAllReportPortalAgentStore();443 await invokeRunRetries();444 await ReportHelper.sendLaunchRequest(ReportHelper.defaultReportStoreKey, {}, false, true);445 }446 resetConsoleLogColor();447 }448449 async function handleExecuteException(err) {450 try {451 await invokeTests(Promise.resolve.bind(Promise));452 await completedCallback();453 ReportHelper.mergeJenkinsResult(RunnerHelper.appRootPath, parallel);454 } catch (retriesErr) {455 console.log(retriesErr);456 log.error('Has error when executing test after retrying', err);457 logListener.error('Has error when executing test after retrying', err);458 printToConsoleWithRedColor(459 '\nHas error in execute test, please view ExecutionLog.log in folder logs for more details!. Execution process will exit after 10s'460 );461 resetConsoleLogColor();462 setTimeout(() => process.exit(1), 10000);463 }464 }465 /**466 *467 * @param {Object} buildInfoData468 * @param {boolean} isRetries469 * Create Mocha ReportPortal Listener470 */471 function crateMochaReportPortalListener(agent, buildInfoData, isParallel = true) {472 if (RunnerHelper.debugMode) {473 log.info('Run Mocha Test In Debug Mode');474 return {};475 }476 log.info('Init Mocha ReportPortal.io listener');477 const { reportDescription, reportTags } = ReportHelper.reportPortalInfo(buildInfoData);478 return new MochaReportListener(479 agent,480 suiteName || 'sampleapp Suite',481 `${reportDescription}\n\n\n\`\`\`${suiteDescription}\`\`\``,482 suiteTags.concat(reportTags),483 isParallel484 );485 }486}487488exports.run = run;489exports.setUpAuthenticateVariable = setUpAuthenticateVariable;490exports.setUpServiceConfigFiles = setUpServiceConfigFiles; ...

Full Screen

Full Screen

RunnerHelperTest.js

Source:RunnerHelperTest.js Github

copy

Full Screen

1/* eslint-disable global-require,max-len,no-undef, no-empty */2delete require.cache[require.resolve('../../helper/runner.helper')];3let { ConfigHelper } = require('../../helper/config.helper');4let { RunnerHelper } = require('../../helper/runner.helper');5const fs = require('fs');6const { ServiceConfig } = require('../../config/service/service.config');7const { assert } = require('chai');8const sinon = require('sinon');9const path = require('path');1011const testConfigFile = path.join(path.resolve(__dirname), 'unittest.config.json');1213const stubListFile = ['a.js', 'b.json', 'c.txt', 'd.log', 'e.js'];14const stubConfigData = {15 anotherKeyDefault: null,16 anotherKey: 'anotherKey',17 loginDomain: 'loginDomain',18 env: 'env',19 namespace: 'namespace',20 baseUrl: 'baseUrl',21 baseAppUrl: 'baseAppUrl',22 baseInvUrl: 'baseInvUrl',23 baseProdUrl: 'baseProdUrl',24 baseRecipeUrl: 'baseRecipeUrl',25 authdomainUrl: 'authdomainUrl',26 vendorUrl: 'vendorUrl',27 storeKey: 'storeKey',28 storeKeys: ['storeKeys', 'storeKeys', 'storeKeys'],29 cookieManager: 'cookieManager',30 securityMethod: 'securityMethod',31 host: 'host',32 port: 'port',33 protocol: 'protocol',34 authenticate: {35 username: 'username',36 password: 'password',37 },38 timeout: 1000,39};4041describe('Unit Test runner.helper.js', function s() {42 let sandbox = sinon.createSandbox();43 let stub = {};44 before(function setUpSuite() {45 // Stub test data46 fs.writeFileSync(testConfigFile, JSON.stringify(stubConfigData));47 });4849 after(function cleanSuite() {50 fs.unlinkSync(testConfigFile);51 delete require.cache[require.resolve('../../helper/runner.helper')];52 });53 beforeEach(function setUpTest() {54 sandbox = sinon.createSandbox();55 stub = sandbox.stub;56 delete require.cache[require.resolve('../../helper/runner.helper')];57 RunnerHelper = require('../../helper/runner.helper').RunnerHelper;58 delete require.cache[require.resolve('../../helper/config.helper')];59 ConfigHelper = require('../../helper/config.helper').ConfigHelper;60 const readdirSyncStub = sandbox.stub(fs, 'readdirSync');61 const statSyncStub = sandbox.stub(fs, 'statSync');62 const readFileSyncStub = sandbox.stub(fs, 'readFileSync');63 readdirSyncStub.withArgs('stubpath').returns(['a.js', 'b.js', 'c']);64 readdirSyncStub.withArgs('stubpath/c').returns(['aa.js', 'bb.js']);65 statSyncStub.withArgs('stubpath/a.js').callsFake(function isDirectory() {66 return { isDirectory: () => false };67 });68 statSyncStub.withArgs('stubpath/b.js').callsFake(function isDirectory() {69 return { isDirectory: () => false };70 });71 statSyncStub.withArgs('stubpath/c').callsFake(function isDirectory() {72 return { isDirectory: () => true };73 });74 statSyncStub.withArgs('stubpath/c/aa.js').callsFake(function isDirectory() {75 return { isDirectory: () => false };76 });77 statSyncStub.withArgs('stubpath/c/bb.js').callsFake(function isDirectory() {78 return { isDirectory: () => false };79 });80 readFileSyncStub81 .withArgs('stubpath/a.js')82 .returns("\nexports.TAGS = ['A', 'Tag With Space', 'P1'];");83 readFileSyncStub.withArgs('stubpath/b.js').returns("\nexports.TAGS = ['B'];");84 readFileSyncStub.withArgs('stubpath/c/aa.js').returns("\nexports.TAGS = ['C', 'P1'];");85 readFileSyncStub.withArgs('stubpath/c/bb.js').returns('\nnothing inside file');86 readFileSyncStub.withArgs(testConfigFile).returns(JSON.stringify(stubConfigData));87 readFileSyncStub.withArgs('debug.config.json').returns(JSON.stringify(stubConfigData));88 });89 afterEach(function resetSandbox() {90 // Restore all the things made through the sandbox91 sandbox.restore();92 });9394 it('Test can set appRootPath', function t() {95 RunnerHelper.appRootPath = 'Stub';96 assert.equal('Stub', RunnerHelper.appRootPath, 'Error in set appRootPath');97 });9899 it('Test cannot set appRootPath twice', function t() {100 RunnerHelper.appRootPath = 'Stub';101 RunnerHelper.appRootPath = 'Another Stub';102 assert.equal('Stub', RunnerHelper.appRootPath, 'Error in set appRootPath');103 });104105 it('Test can set testFolderPath', function t() {106 RunnerHelper.testFolderPath = 'Stub';107 assert.equal('Stub', RunnerHelper.testFolderPath, 'Error in set appRootPath');108 });109110 it('Test cannot set testFolderPath twice', function t() {111 RunnerHelper.testFolderPath = 'Stub';112 RunnerHelper.testFolderPath = 'Another Stub';113 assert.equal('Stub', RunnerHelper.testFolderPath, 'Error in set appRootPath');114 });115116 it('Test can set restServiceConfigFilePath', function t() {117 RunnerHelper.restServiceConfigFilePath = 'Stub';118 assert.equal('Stub', RunnerHelper.restServiceConfigFilePath, 'Error in set appRootPath');119 });120121 it('Test cannot set restServiceConfigFilePath twice', function t() {122 RunnerHelper.restServiceConfigFilePath = 'Stub';123 RunnerHelper.restServiceConfigFilePath = 'Another Stub';124 assert.equal('Stub', RunnerHelper.restServiceConfigFilePath, 'Error in set appRootPath');125 });126127 it('Test get serviceConfig from raw JSON', function t() {128 const config = RunnerHelper.getServiceConfigFromJson({ a: 1111 });129 assert.instanceOf(config, ServiceConfig, 'Error in create service config from raw JSON');130 });131132 it('Test cannot set serviceConfig from raw JSON twice', function t() {133 const configFirst = RunnerHelper.getServiceConfigFromJson({ a: 11 });134 const configSecond = RunnerHelper.getServiceConfigFromJson({ a: 22 });135 assert.instanceOf(configFirst, ServiceConfig, 'Error in create service config from raw JSON');136 assert.instanceOf(configSecond, ServiceConfig, 'Error in create service config from raw JSON');137 assert.equal(138 configFirst.getConfigData('a'),139 configSecond.getConfigData('a'),140 'Error in persitent service config from raw JSON'141 );142 });143144 it('Test can set authenticate username', function t() {145 RunnerHelper.authenticateUserName = 'a';146 assert.equal(RunnerHelper.authenticateUserName, 'a', 'Error in set authenticate username');147 });148149 it('Test cannot set authenticate username twice', function t() {150 ConfigHelper.restAuthenticateUserName = 'a';151 ConfigHelper.restAuthenticateUserName = 'b';152 assert.equal(153 ConfigHelper.restAuthenticateUserName,154 'a',155 'Error in persitent authenticate username'156 );157 });158159 it('Test can set authenticate password', function t() {160 RunnerHelper.authenticatePassword = 'a';161 assert.equal(RunnerHelper.authenticatePassword, 'a', 'Error in set authenticate username');162 });163164 it('Test cannot set authenticate password twice', function t() {165 ConfigHelper.restAuthenticatePassword = 'a';166 ConfigHelper.restAuthenticatePassword = 'b';167 assert.equal(168 ConfigHelper.restAuthenticatePassword,169 'a',170 'Error in persitent authenticate username'171 );172 });173174 it('Test can get serviceConfigDebug without configPath', function t() {175 const runnerHelperSpy = sandbox.spy(RunnerHelper, 'getDebugModeConfig');176 const pathJoinStub = sandbox.stub(path, 'join');177 pathJoinStub.returns('debug.config.json');178 const config = RunnerHelper.getServiceConfig();179 assert.equal(runnerHelperSpy.calledOnce, true, 'Error in get debug config');180 assert.instanceOf(config, ServiceConfig, 'Error in create service config from debug config');181 });182183 it('Test throw exception if get serviceConfig without restServiceConfigFilePath and debug.config.json', function t() {184 const pathJoinStub = stub(path, 'join');185 pathJoinStub.returns('nothing.file.json');186 const config = () => {187 return RunnerHelper.getServiceConfig();188 };189 assert.throws(190 config,191 Error,192 'Missing debug.config.json file in config folder',193 'Error in throw exception when missing debug.config.json in get ServiceConfig'194 );195 });196197 it('Test can get serviceConfig restServiceConfigFilePath', function t() {198 RunnerHelper.restServiceConfigFilePath = testConfigFile;199 const config = RunnerHelper.getServiceConfig();200 assert.instanceOf(config, ServiceConfig, 'Error in get ServiceConfig');201 assert.equal(config.baseUrl, stubConfigData.baseUrl, 'Error in get ServiceConfig');202 });203204 it('Test can check object contain method', function t() {205 const StubObject = function Stub() {};206 StubObject.prototype.test = 1;207 const actualValue = RunnerHelper.isContainMethod(new StubObject(), 'test');208 assert.equal(actualValue, true, 'Has error in check object contains method');209 });210211 it('Test can filter file by extension name', async function t() {212 const listFiles = RunnerHelper.filterFileByExtension(stubListFile, '.js');213 assert.deepEqual(listFiles, ['a.js', 'e.js'], 'Error in filter file by extension');214 });215216 it('Test can get all files in folder', async function t() {217 // Arrange218 const listActualFiles = [];219 // Act220 RunnerHelper.getAllFileInFolder('stubpath', listActualFiles);221 // Assert222 assert.deepEqual(listActualFiles, [223 'stubpath/a.js',224 'stubpath/b.js',225 'stubpath/c/aa.js',226 'stubpath/c/bb.js',227 ]);228 });229230 it('Test can get all files by it tags data inside and test without tag data', async function t() {231 const listTestFiles = [];232 const actualTestFiles = RunnerHelper.filterFileByExtensionAndTag(233 'stubpath',234 ['A'],235 '.js',236 listTestFiles237 );238 assert.deepEqual(actualTestFiles, ['stubpath/a.js', 'stubpath/c/bb.js']);239 });240241 it('Test can get all files if run without tag', async function t() {242 const listTestFiles = [];243 const actualTestFiles = RunnerHelper.filterFileByExtensionAndTag(244 'stubpath',245 [],246 '.js',247 listTestFiles248 );249 assert.deepEqual(actualTestFiles, [250 'stubpath/a.js',251 'stubpath/b.js',252 'stubpath/c/aa.js',253 'stubpath/c/bb.js',254 ]);255 });256257 it('Test can get all files by tag has space inside data inside ', async function t() {258 const listTestFiles = [];259 const actualTestFiles = RunnerHelper.filterFileByExtensionAndTag(260 'stubpath',261 ['Tag With Space'],262 '.js',263 listTestFiles264 );265 assert.deepEqual(actualTestFiles, ['stubpath/a.js', 'stubpath/c/bb.js']);266 });267268 it('Test can get all files by tag has number inside data inside ', async function t() {269 const listTestFiles = [];270 const actualTestFiles = RunnerHelper.filterFileByExtensionAndTag(271 'stubpath',272 ['P1'],273 '.js',274 listTestFiles275 );276 assert.deepEqual(actualTestFiles, ['stubpath/a.js', 'stubpath/c/aa.js', 'stubpath/c/bb.js']);277 }); ...

Full Screen

Full Screen

runner.helper.js

Source:runner.helper.js Github

copy

Full Screen

1const fs = require('fs');2const path = require('path');3const { ServiceConfig, SftpConfig } = require('../config/service');45let restServiceConfigFilePath = null;6let sftpServiceConfigFilePath = null;7let appRootPath = null;8let testFolderPath = null;9let rawConfigObject = null;10let rawSftpConfigObject = null;11let debugMode = false;12let restServiceConfigObject = null;13let sftpServiceConfigObject = null;14const checkIfFileHasContainTag = (tagNames, tag) => {15 tag = tag.replace(/'/gm, '');16 if (tagNames.includes(tag)) {17 return true;18 }19 return false;20};2122class RunnerHelper {23 static getAllFileInFolder(folderPath, listFile) {24 fs.readdirSync(folderPath).forEach((f) => {25 const currentPath = path.join(folderPath, f);26 const isDirectory = fs.statSync(currentPath).isDirectory();27 isDirectory ? this.getAllFileInFolder(currentPath, listFile) : listFile.push(currentPath);28 });29 }30 static filterFileByExtensionAndTag(filePath, tags, fileExtension, listTestFiles) {31 RunnerHelper.getAllFileInFolder(filePath, listTestFiles);32 listTestFiles = RunnerHelper.filterFileByExtension(listTestFiles, fileExtension);33 listTestFiles = RunnerHelper.filterFileByTag(listTestFiles, tags);34 return listTestFiles;35 }3637 static filterFileByTag(listFiles, tagNames) {38 // return all file if run without tags39 if (!tagNames.length) {40 return listFiles;41 }42 return listFiles.filter((file) => {43 const hasRawTagsInTestFile = fs44 .readFileSync(file)45 .toString()46 .match(/.*exports.TAGS.*;/gm);47 // Will add default tag if not define tag48 const rawTagsInTestFile = hasRawTagsInTestFile || `["'${tagNames[0]}'"]`;49 const listTagsInFile = rawTagsInTestFile.toString().match(/'(-*\w\s*)+'/gm);50 /**51 * Check if file contains tag to run52 * It will return the array contain boolean53 * If file contains tag54 */55 const fileHasTagToRunMapping = listTagsInFile.map((tag) => {56 return checkIfFileHasContainTag(tagNames, tag);57 });5859 return fileHasTagToRunMapping.includes(true);60 });61 }6263 static filterFileByExtension(listFiles, extension) {64 return listFiles.filter((file) => {65 const fileName = path.basename(file);66 return fileName.substr(-3) === extension;67 });68 }6970 static isContainMethod(object, method) {71 const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(object));72 return methods.includes(method);73 }7475 static getServiceConfig() {76 // Singleton instance service config object one time77 // Avoid having memory leak78 if (!restServiceConfigObject) restServiceConfigObject = new ServiceConfig(RunnerHelper.restServiceConfigFilePath);79 if (RunnerHelper.restServiceConfigFilePath) return restServiceConfigObject;80 return RunnerHelper.getDebugModeConfig();81 }8283 static getServiceConfigFromJson(configObject) {84 if (!rawConfigObject) rawConfigObject = configObject;85 return new ServiceConfig(rawConfigObject, false);86 }8788 static getSftpConfig() {89 if (!sftpServiceConfigObject) sftpServiceConfigObject = new SftpConfig(RunnerHelper.sftpServiceConfigFilePath);90 return sftpServiceConfigObject;91 }9293 static getSftpConfigFromJson(configObject) {94 rawSftpConfigObject = rawSftpConfigObject || configObject;95 return new SftpConfig(rawSftpConfigObject, false);96 }9798 static getDebugModeConfig() {99 try {100 const debugConfigPath = path.join(101 path.resolve(__dirname),102 '..',103 '..',104 'config',105 'runner',106 'rest.service',107 'debug.config.json'108 );109 return new ServiceConfig(debugConfigPath);110 } catch (error) {111 throw new Error('Missing debug.config.json file in config folder');112 }113 }114115 static get restServiceConfigFilePath() {116 return restServiceConfigFilePath;117 }118119 static set restServiceConfigFilePath(filePath) {120 // Check to allow set config file path one time when executing test121 if (!restServiceConfigFilePath && filePath) {122 restServiceConfigFilePath = filePath;123 }124 }125126 static get sftpServiceConfigFilePath() {127 return sftpServiceConfigFilePath;128 }129130 static set sftpServiceConfigFilePath(filePath) {131 // Check to allow set config file path one time when executing test132 if (!sftpServiceConfigFilePath && filePath) {133 sftpServiceConfigFilePath = filePath;134 }135 }136137 static get appRootPath() {138 return appRootPath;139 }140141 static set appRootPath(rootPath) {142 // Check to allow set config file path one time when executing test143 if (!appRootPath && rootPath) {144 appRootPath = rootPath;145 }146 }147148 static get testFolderPath() {149 return testFolderPath;150 }151152 static set testFolderPath(folderPath) {153 // Check to allow set config file path one time when executing test154 if (!testFolderPath && folderPath) {155 testFolderPath = folderPath;156 }157 }158159 static get debugMode() {160 return debugMode;161 }162163 static set debugMode(mode) {164 debugMode = mode;165 }166167 static deleteFolderRecursive(folderPath) {168 if (fs.existsSync(folderPath)) {169 fs.readdirSync(folderPath).forEach((file) => {170 const curPath = `${folderPath}/${file}`;171 if (fs.lstatSync(curPath).isDirectory()) {172 // recurse173 RunnerHelper.deleteFolderRecursive(curPath);174 } else {175 // delete file176 fs.unlinkSync(curPath);177 }178 });179 fs.rmdirSync(folderPath);180 }181 }182}183 ...

Full Screen

Full Screen

execute.js

Source:execute.js Github

copy

Full Screen

1const Mocha = require('mocha');2const path = require('path');3const { RunnerHelper } = require('../helper/runner.helper');45const GlobalHook = require.resolve('./hook');67const filterListTestFiles = (filePath, isSingleFile, fileExtension) => {8 let listTestFiles = [];9 if (Array.isArray(filePath)) {10 listTestFiles = filePath;11 } else if (!isSingleFile) {12 listTestFiles = RunnerHelper.filterFileByExtensionAndTag(filePath, this.tags, fileExtension, listTestFiles);13 } else {14 listTestFiles.push(filePath);15 }16 return listTestFiles;17};1819const cleanCacheTestFiles = (listTestFiles) => {20 listTestFiles.forEach((testFilePath) => {21 console.log(`Reset state ${testFilePath} before run retries`); // eslint-disable-line no-console22 Object.keys(require.cache).forEach((currentCacheFilePath) => {23 const cacheFileName = path.basename(currentCacheFilePath);24 const retriesTestFileName = path.basename(testFilePath);25 if (cacheFileName === retriesTestFileName) {26 delete require.cache[currentCacheFilePath];27 }28 });29 });30};3132class Execute {33 constructor({ isRetries }) {34 this.completeCallBack = [35 async (...args) => {36 process.exitCode = args[0] ? 1 : 0;37 }38 ];39 this.isRetries = isRetries;40 this.tags = [];41 this.runner = {};42 this.mocha = new Mocha();43 this.mocha.addFile(GlobalHook);44 }4546 addTestFiles(filePath, fileExtension, isSingleFile = false) {47 const listTestFiles = filterListTestFiles(filePath, isSingleFile, fileExtension);48 if (this.isRetries) {49 cleanCacheTestFiles(listTestFiles);50 }51 console.log(`Execute suite with ${listTestFiles.length} test files`); // eslint-disable-line no-console52 listTestFiles.forEach((file) => {53 console.log(`Add ${file} into suite `); // eslint-disable-line no-console54 this.mocha.addFile(file);55 });56 return this;57 }5859 addTag(tag) {60 this.tags = this.tags.concat(tag);61 return this;62 }6364 addCompleteCallBack(completeCallBack) {65 this.completeCallBack.push(completeCallBack);66 return this;67 }6869 addReporter(reportType, reportOptions) {70 this.mocha.reporter(reportType, reportOptions);71 return this;72 }7374 addTestListener(listener) {75 if (RunnerHelper.isContainMethod(listener, 'listen')) {76 listener.runner = this.runner;77 listener.listen();78 }79 return this;80 }8182 setTimeout(timeout) {83 const config = RunnerHelper.getServiceConfig();84 timeout = timeout || config.timeout;85 this.mocha.timeout(timeout);86 return this;87 }8889 run(90 runnerConfig = {91 listener: { runner: () => {}, listen: () => {} }92 },93 maxListeners = 51294 ) {95 /**96 * Default Node.JS allow maximum 10 listeners add to EventEmmiter97 * and we set it to 100 for allowing multiple listeners use in log98 *99 * */100 process.setMaxListeners(maxListeners);101 this.runner = this.mocha.run((...args) => {102 this.completeCallBack.forEach((callbackComplete) => {103 callbackComplete(...args);104 });105 });106 this.addTestListener(runnerConfig.listener);107 return this;108 }109}110 ...

Full Screen

Full Screen

finder.test.mjs

Source:finder.test.mjs Github

copy

Full Screen

...10 tags: ['finder']11 }, async () => {12 const p = new URL(import.meta.url).pathname;13 const dir = resolve(p, '..', '..', 'test-data', 'finder');14 const actual = await listTestFiles(15 dir,16 '.test.mjs',17 ['node_modules']18 );19 deepStrictEqual(actual, [20 resolve(dir, 'first', 'index.test.mjs'),21 resolve(dir, 'first', 'second', 'index.test.mjs'),22 resolve(dir, 'index.test.mjs'),23 ]);24 });25 test({26 name: 'prepend "." if ext argument starts without it',27 tags: ['finder']28 }, async () => {29 const p = new URL(import.meta.url).pathname;30 const dir = resolve(p, '..', '..', 'test-data', 'finder');31 const actual = await listTestFiles(32 dir,33 'test.mjs',34 ['node_modules']35 );36 deepStrictEqual(actual, [37 resolve(dir, 'first', 'index.test.mjs'),38 resolve(dir, 'first', 'second', 'index.test.mjs'),39 resolve(dir, 'index.test.mjs'),40 ]);41 });42 test({43 name: 'exclude "first" and "node_modules"',44 tags: ['finder']45 }, async () => {46 const p = new URL(import.meta.url).pathname;47 const dir = resolve(p, '..', '..', 'test-data', 'finder');48 const actual = await listTestFiles(49 dir,50 'test.mjs',51 ['first']52 );53 deepStrictEqual(actual, [54 resolve(dir, 'index.test.mjs'),55 ]);56 });...

Full Screen

Full Screen

finder.mjs

Source:finder.mjs Github

copy

Full Screen

...13 if (entry.isDirectory()) {14 if (excludeDirs.includes(entry.name)) {15 continue;16 }17 const fs = await listTestFiles(join(path, entry.name), ext, excludeDirs);18 files.push(...fs);19 continue;20 }21 if (entry.name.endsWith(ext)) {22 files.push(join(path, entry.name));23 }24 }25 return files;26};27/**28 * @param {string} path29 * @param {string} ext30 * @param {string[]} excludeDirs31 * @return {Promise<string[]>}...

Full Screen

Full Screen

testMotor.js

Source:testMotor.js Github

copy

Full Screen

...5class TestMotor{6 constructor(config){7 this.config = config;8 this.allTestGroup = [];9 this.allTestFiles = this.listTestFiles();10 this.createAllTestGroup();11 }12 createTestGroup(group){13 this.allTestGroup.push(new TestGroup(group, this.config));14 }15 listTestFiles(){16 let files = [];17 fs.readdirSync(this.config.testFolder).forEach(file => {(path.extname(file) == '.json') ? files.push(file) : ''})18 return files;19 }20 createAllTestGroup(){21 this.allTestFiles.forEach(file => {22 let fileParser = new FileParser(file, this.config);23 let group = fileParser.getAllTest();24 this.createTestGroup(group);25 });26 }27}...

Full Screen

Full Screen

index.mjs

Source:index.mjs Github

copy

Full Screen

...6 */7export const schist = config => {8 return {9 run: async () => {10 const files = await listTestFiles(config.path);11 const tests = await registerTestSuite(files);12 const result = await runTest(tests);13 if (result.failedData.length === 0) {14 console.log('ok');15 return;16 }17 for (const datum of result.failedData) {18 console.group(datum.name);19 console.log(`${datum.path}\n`);20 console.log(datum.error);21 console.groupEnd();22 }23 }24 };...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const fs = require('fs');2const path = require('path');3const playwright = require('playwright');4const { listTestFiles } = require('playwright/lib/test/runner');5const { TestType } = require('playwright/lib/test/types');6(async () => {7 const browserType = 'chromium';8 const projectDir = path.join(__dirname, 'tests');9 const testFiles = await listTestFiles(projectDir, {10 });11 console.log(testFiles);12})();13const { test } = require('@playwright/test');14test('test', async ({ page }) => {15 const title = page.locator('text=Playwright');16 await title.isVisible();17});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { test, expect } = require('@playwright/test');2const { listTestFiles } = require('@playwright/test/lib/test');3test('listTestFiles', async ({}, testInfo) => {4 const files = await listTestFiles();5 console.log(files);6 expect(files).toContain('test.js');7});8 1 passed (1s)9const { test } = require('@playwright/test');10test('basic test', async ({ page }) => {11 await expect(page.locator('text=Get started')).toBeVisible();12});13const { test } = require('@playwright/test');14test.describe('My test suite', () => {15 test('basic test', async ({ page }) => {16 await expect(page.locator('text=Get started')).toBeVisible();17 });18});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('@playwright/test');2const { test } = require('@playwright/test');3const testFiles = listTestFiles('./tests');4console.log(testFiles);5test('test', async ({ page }) => {6 const title = page.locator('text=Playwright');7 await title.waitFor();8});9test('test1', async ({ page }) => {10 const title = page.locator('text=Playwright');11 await title.waitFor();12});13test('test2', async ({ page }) => {14 const title = page.locator('text=Playwright');15 await title.waitFor();16});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('@playwright/test');2const files = await listTestFiles(['**/*.spec.js']);3console.log(files);4const { test } = require('@playwright/test');5test('test', () => {6 console.log('test');7});8import { test } from '@playwright/test';9test('test', () => {10 console.log('test');11});12import { test } from '@playwright/test';13test('test', () => {14 console.log('test');15});16import { test } from '@playwright/test';17test('test', () => {18 console.log('test');19});20import { test } from '@playwright/test';21test('test', () => {22 console.log('test');23});24import { test } from '@playwright/test';25test('test', () => {26 console.log('test');27});28import { test } from '@playwright/test';29test('test', () => {30 console.log('test');31});32import { test } from '@playwright/test';33test('test', () => {34 console.log('test');35});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('@playwright/test');2(async () => {3 const files = await listTestFiles();4 console.log(files);5})();6const { test, listTestFiles } = require('@playwright/test');7test('List all test files', async ({}) => {8 const files = await listTestFiles();9 console.log(files);10});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('@playwright/test');2(async () => {3 const files = await listTestFiles('**/tests/**/*.spec.ts');4 console.log(files);5})();6import { test } from '@playwright/test';7test('test1', async ({ page }) => {8 expect(await page.title()).toBe('Playwright');9});10import { test } from '@playwright/test';11test('test2', async ({ page }) => {12 expect(await page.title()).toBe('Playwright');13});14import { test } from '@playwright/test';15test('test3', async ({ page }) => {16 expect(await page.title()).toBe('Playwright');17});18import { test } from '@playwright/test';19test('test4', async ({ page }) => {20 expect(await page.title()).toBe('Playwright');21});22import { test } from '@playwright/test';23test('test5', async ({ page }) => {24 expect(await page.title()).toBe('Playwright');25});26import { test } from '@playwright/test';27test('test6', async ({ page }) => {28 expect(await page.title()).toBe('Playwright');29});30import { test } from '@playwright/test';31test('test7', async ({ page }) => {32 expect(await page.title()).toBe('Playwright');33});34import { test } from '@playwright/test';35test('test8', async ({ page }) => {36 expect(await page.title()).toBe('Playwright');37});38import { test } from '@playwright/test';39test('test9',

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('@playwright/test/lib/utils/testrunner/TestRunner');2const testFiles = listTestFiles('test');3console.log(testFiles);4const { test, expect } = require('@playwright/test');5test('test', async ({ page }) => {6 const title = page.locator('text=Playwright');7 await expect(title).toBeVisible();8});

Full Screen

Using AI Code Generation

copy

Full Screen

1const { listTestFiles } = require('playwright-core/lib/test/runner');2const files = await listTestFiles('test/**/*.spec.js');3console.log(files);4const { test, expect } = require('@playwright/test');5test('first test', async ({ page }) => {6 const title = page.locator('.navbar__inner .navbar__title');7 await expect(title).toHaveText('Playwright');8});9test('second test', async ({ page }) => {10 const title = page.locator('.navbar__inner .navbar__title');11 await expect(title).toHaveText('Playwright');12});13 2 passed (2s)

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful