How to use redirectChain method in Puppeteer

Best JavaScript code snippet using puppeteer

network.spec.js

Source:network.spec.js Github

copy

Full Screen

...152 });153 it('should throw when requesting body of redirected response', async({page, server}) => {154 server.setRedirect('/foo.html', '/empty.html');155 const response = await page.goto(server.PREFIX + '/foo.html');156 const redirectChain = response.request().redirectChain();157 expect(redirectChain.length).toBe(1);158 const redirected = redirectChain[0].response();159 expect(redirected.status()).toBe(302);160 let error = null;161 await redirected.text().catch(e => error = e);162 expect(error.message).toContain('Response body is unavailable for redirect responses');163 });164 it('should wait until response completes', async({page, server}) => {165 await page.goto(server.EMPTY_PAGE);166 // Setup server to trap request.167 let serverResponse = null;168 server.setRoute('/get', (req, res) => {169 serverResponse = res;170 // In Firefox, |fetch| will be hanging until it receives |Content-Type| header171 // from server.172 res.setHeader('Content-Type', 'text/plain; charset=utf-8');173 res.write('hello ');174 });175 // Setup page to trap response.176 let requestFinished = false;177 page.on('requestfinished', r => requestFinished = requestFinished || r.url().includes('/get'));178 // send request and wait for server response179 const [pageResponse] = await Promise.all([180 page.waitForResponse(r => !utils.isFavicon(r.request())),181 page.evaluate(() => fetch('./get', { method: 'GET'})),182 server.waitForRequest('/get'),183 ]);184 expect(serverResponse).toBeTruthy();185 expect(pageResponse).toBeTruthy();186 expect(pageResponse.status()).toBe(200);187 expect(requestFinished).toBe(false);188 const responseText = pageResponse.text();189 // Write part of the response and wait for it to be flushed.190 await new Promise(x => serverResponse.write('wor', x));191 // Finish response.192 await new Promise(x => serverResponse.end('ld!', x));193 expect(await responseText).toBe('hello world!');194 });195 });196 describe('Response.json', function() {197 it('should work', async({page, server}) => {198 const response = await page.goto(server.PREFIX + '/simple.json');199 expect(await response.json()).toEqual({foo: 'bar'});200 });201 });202 describe('Response.buffer', function() {203 it('should work', async({page, server}) => {204 const response = await page.goto(server.PREFIX + '/pptr.png');205 const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));206 const responseBuffer = await response.buffer();207 expect(responseBuffer.equals(imageBuffer)).toBe(true);208 });209 it('should work with compression', async({page, server}) => {210 server.enableGzip('/pptr.png');211 const response = await page.goto(server.PREFIX + '/pptr.png');212 const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));213 const responseBuffer = await response.buffer();214 expect(responseBuffer.equals(imageBuffer)).toBe(true);215 });216 });217 describe('Response.statusText', function() {218 it('should work', async({page, server}) => {219 server.setRoute('/cool', (req, res) => {220 res.writeHead(200, 'cool!');221 res.end();222 });223 const response = await page.goto(server.PREFIX + '/cool');224 expect(response.statusText()).toBe('cool!');225 });226 });227 describe('Network Events', function() {228 it('Page.Events.Request', async({page, server}) => {229 const requests = [];230 page.on('request', request => requests.push(request));231 await page.goto(server.EMPTY_PAGE);232 expect(requests.length).toBe(1);233 expect(requests[0].url()).toBe(server.EMPTY_PAGE);234 expect(requests[0].resourceType()).toBe('document');235 expect(requests[0].method()).toBe('GET');236 expect(requests[0].response()).toBeTruthy();237 expect(requests[0].frame() === page.mainFrame()).toBe(true);238 expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);239 });240 it('Page.Events.Response', async({page, server}) => {241 const responses = [];242 page.on('response', response => responses.push(response));243 await page.goto(server.EMPTY_PAGE);244 expect(responses.length).toBe(1);245 expect(responses[0].url()).toBe(server.EMPTY_PAGE);246 expect(responses[0].status()).toBe(200);247 expect(responses[0].ok()).toBe(true);248 expect(responses[0].request()).toBeTruthy();249 const remoteAddress = responses[0].remoteAddress();250 // Either IPv6 or IPv4, depending on environment.251 expect(remoteAddress.ip.includes('::1') || remoteAddress.ip === '127.0.0.1').toBe(true);252 expect(remoteAddress.port).toBe(server.PORT);253 });254 it('Page.Events.RequestFailed', async({page, server}) => {255 await page.setRequestInterception(true);256 page.on('request', request => {257 if (request.url().endsWith('css'))258 request.abort();259 else260 request.continue();261 });262 const failedRequests = [];263 page.on('requestfailed', request => failedRequests.push(request));264 await page.goto(server.PREFIX + '/one-style.html');265 expect(failedRequests.length).toBe(1);266 expect(failedRequests[0].url()).toContain('one-style.css');267 expect(failedRequests[0].response()).toBe(null);268 expect(failedRequests[0].resourceType()).toBe('stylesheet');269 if (CHROME)270 expect(failedRequests[0].failure().errorText).toBe('net::ERR_FAILED');271 else272 expect(failedRequests[0].failure().errorText).toBe('NS_ERROR_FAILURE');273 expect(failedRequests[0].frame()).toBeTruthy();274 });275 it('Page.Events.RequestFinished', async({page, server}) => {276 const requests = [];277 page.on('requestfinished', request => requests.push(request));278 await page.goto(server.EMPTY_PAGE);279 expect(requests.length).toBe(1);280 expect(requests[0].url()).toBe(server.EMPTY_PAGE);281 expect(requests[0].response()).toBeTruthy();282 expect(requests[0].frame() === page.mainFrame()).toBe(true);283 expect(requests[0].frame().url()).toBe(server.EMPTY_PAGE);284 });285 it('should fire events in proper order', async({page, server}) => {286 const events = [];287 page.on('request', request => events.push('request'));288 page.on('response', response => events.push('response'));289 page.on('requestfinished', request => events.push('requestfinished'));290 await page.goto(server.EMPTY_PAGE);291 expect(events).toEqual(['request', 'response', 'requestfinished']);292 });293 it('should support redirects', async({page, server}) => {294 const events = [];295 page.on('request', request => events.push(`${request.method()} ${request.url()}`));296 page.on('response', response => events.push(`${response.status()} ${response.url()}`));297 page.on('requestfinished', request => events.push(`DONE ${request.url()}`));298 page.on('requestfailed', request => events.push(`FAIL ${request.url()}`));299 server.setRedirect('/foo.html', '/empty.html');300 const FOO_URL = server.PREFIX + '/foo.html';301 const response = await page.goto(FOO_URL);302 expect(events).toEqual([303 `GET ${FOO_URL}`,304 `302 ${FOO_URL}`,305 `DONE ${FOO_URL}`,306 `GET ${server.EMPTY_PAGE}`,307 `200 ${server.EMPTY_PAGE}`,308 `DONE ${server.EMPTY_PAGE}`309 ]);310 // Check redirect chain311 const redirectChain = response.request().redirectChain();312 expect(redirectChain.length).toBe(1);313 expect(redirectChain[0].url()).toContain('/foo.html');314 expect(redirectChain[0].response().remoteAddress().port).toBe(server.PORT);315 });316 });317 describe('Request.isNavigationRequest', () => {318 it('should work', async({page, server}) => {319 const requests = new Map();320 page.on('request', request => requests.set(request.url().split('/').pop(), request));321 server.setRedirect('/rrredirect', '/frames/one-frame.html');322 await page.goto(server.PREFIX + '/rrredirect');323 expect(requests.get('rrredirect').isNavigationRequest()).toBe(true);324 expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true);325 expect(requests.get('frame.html').isNavigationRequest()).toBe(true);326 expect(requests.get('script.js').isNavigationRequest()).toBe(false);327 expect(requests.get('style.css').isNavigationRequest()).toBe(false);328 });329 it('should work with request interception', async({page, server}) => {330 const requests = new Map();331 page.on('request', request => {332 requests.set(request.url().split('/').pop(), request);333 request.continue();334 });335 await page.setRequestInterception(true);336 server.setRedirect('/rrredirect', '/frames/one-frame.html');337 await page.goto(server.PREFIX + '/rrredirect');338 expect(requests.get('rrredirect').isNavigationRequest()).toBe(true);339 expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true);340 expect(requests.get('frame.html').isNavigationRequest()).toBe(true);341 expect(requests.get('script.js').isNavigationRequest()).toBe(false);342 expect(requests.get('style.css').isNavigationRequest()).toBe(false);343 });344 it('should work when navigating to image', async({page, server}) => {345 const requests = [];346 page.on('request', request => requests.push(request));347 await page.goto(server.PREFIX + '/pptr.png');348 expect(requests[0].isNavigationRequest()).toBe(true);349 });350 });351 describe('Page.setRequestInterception', function() {352 it('should intercept', async({page, server}) => {353 await page.setRequestInterception(true);354 page.on('request', request => {355 if (utils.isFavicon(request)) {356 request.continue();357 return;358 }359 expect(request.url()).toContain('empty.html');360 expect(request.headers()['user-agent']).toBeTruthy();361 expect(request.method()).toBe('GET');362 expect(request.postData()).toBe(undefined);363 expect(request.isNavigationRequest()).toBe(true);364 expect(request.resourceType()).toBe('document');365 expect(request.frame() === page.mainFrame()).toBe(true);366 expect(request.frame().url()).toBe('about:blank');367 request.continue();368 });369 const response = await page.goto(server.EMPTY_PAGE);370 expect(response.ok()).toBe(true);371 expect(response.remoteAddress().port).toBe(server.PORT);372 });373 it('should work when POST is redirected with 302', async({page, server}) => {374 server.setRedirect('/rredirect', '/empty.html');375 await page.goto(server.EMPTY_PAGE);376 await page.setRequestInterception(true);377 page.on('request', request => request.continue());378 await page.setContent(`379 <form action='/rredirect' method='post'>380 <input type="hidden" id="foo" name="foo" value="FOOBAR">381 </form>382 `);383 await Promise.all([384 page.$eval('form', form => form.submit()),385 page.waitForNavigation()386 ]);387 });388 // @see https://github.com/GoogleChrome/puppeteer/issues/3973389 xit('should work when header manipulation headers with redirect', async({page, server}) => {390 server.setRedirect('/rrredirect', '/empty.html');391 await page.setRequestInterception(true);392 page.on('request', request => {393 const headers = Object.assign({}, request.headers(), {394 foo: 'bar'395 });396 request.continue({ headers });397 });398 await page.goto(server.PREFIX + '/rrredirect');399 });400 it('should contain referer header', async({page, server}) => {401 await page.setRequestInterception(true);402 const requests = [];403 page.on('request', request => {404 if (!utils.isFavicon(request))405 requests.push(request);406 request.continue();407 });408 await page.goto(server.PREFIX + '/one-style.html');409 expect(requests[1].url()).toContain('/one-style.css');410 expect(requests[1].headers().referer).toContain('/one-style.html');411 });412 it('should properly return navigation response when URL has cookies', async({page, server}) => {413 // Setup cookie.414 await page.goto(server.EMPTY_PAGE);415 await page.setCookie({ name: 'foo', value: 'bar'});416 // Setup request interception.417 await page.setRequestInterception(true);418 page.on('request', request => request.continue());419 const response = await page.reload();420 expect(response.status()).toBe(200);421 });422 it('should stop intercepting', async({page, server}) => {423 await page.setRequestInterception(true);424 page.once('request', request => request.continue());425 await page.goto(server.EMPTY_PAGE);426 await page.setRequestInterception(false);427 await page.goto(server.EMPTY_PAGE);428 });429 it('should show custom HTTP headers', async({page, server}) => {430 await page.setExtraHTTPHeaders({431 foo: 'bar'432 });433 await page.setRequestInterception(true);434 page.on('request', request => {435 expect(request.headers()['foo']).toBe('bar');436 request.continue();437 });438 const response = await page.goto(server.EMPTY_PAGE);439 expect(response.ok()).toBe(true);440 });441 it('should works with customizing referer headers', async({page, server}) => {442 await page.setExtraHTTPHeaders({ 'referer': server.EMPTY_PAGE });443 await page.setRequestInterception(true);444 page.on('request', request => {445 expect(request.headers()['referer']).toBe(server.EMPTY_PAGE);446 request.continue();447 });448 const response = await page.goto(server.EMPTY_PAGE);449 expect(response.ok()).toBe(true);450 });451 it('should be abortable', async({page, server}) => {452 await page.setRequestInterception(true);453 page.on('request', request => {454 if (request.url().endsWith('.css'))455 request.abort();456 else457 request.continue();458 });459 let failedRequests = 0;460 page.on('requestfailed', event => ++failedRequests);461 const response = await page.goto(server.PREFIX + '/one-style.html');462 expect(response.ok()).toBe(true);463 expect(response.request().failure()).toBe(null);464 expect(failedRequests).toBe(1);465 });466 it_fails_ffox('should be abortable with custom error codes', async({page, server}) => {467 await page.setRequestInterception(true);468 page.on('request', request => {469 request.abort('internetdisconnected');470 });471 let failedRequest = null;472 page.on('requestfailed', request => failedRequest = request);473 await page.goto(server.EMPTY_PAGE).catch(e => {});474 expect(failedRequest).toBeTruthy();475 expect(failedRequest.failure().errorText).toBe('net::ERR_INTERNET_DISCONNECTED');476 });477 it('should send referer', async({page, server}) => {478 await page.setExtraHTTPHeaders({479 referer: 'http://google.com/'480 });481 await page.setRequestInterception(true);482 page.on('request', request => request.continue());483 const [request] = await Promise.all([484 server.waitForRequest('/grid.html'),485 page.goto(server.PREFIX + '/grid.html'),486 ]);487 expect(request.headers['referer']).toBe('http://google.com/');488 });489 it('should fail navigation when aborting main resource', async({page, server}) => {490 await page.setRequestInterception(true);491 page.on('request', request => request.abort());492 let error = null;493 await page.goto(server.EMPTY_PAGE).catch(e => error = e);494 expect(error).toBeTruthy();495 if (CHROME)496 expect(error.message).toContain('net::ERR_FAILED');497 else498 expect(error.message).toContain('NS_ERROR_FAILURE');499 });500 it('should work with redirects', async({page, server}) => {501 await page.setRequestInterception(true);502 const requests = [];503 page.on('request', request => {504 request.continue();505 requests.push(request);506 });507 server.setRedirect('/non-existing-page.html', '/non-existing-page-2.html');508 server.setRedirect('/non-existing-page-2.html', '/non-existing-page-3.html');509 server.setRedirect('/non-existing-page-3.html', '/non-existing-page-4.html');510 server.setRedirect('/non-existing-page-4.html', '/empty.html');511 const response = await page.goto(server.PREFIX + '/non-existing-page.html');512 expect(response.status()).toBe(200);513 expect(response.url()).toContain('empty.html');514 expect(requests.length).toBe(5);515 expect(requests[2].resourceType()).toBe('document');516 // Check redirect chain517 const redirectChain = response.request().redirectChain();518 expect(redirectChain.length).toBe(4);519 expect(redirectChain[0].url()).toContain('/non-existing-page.html');520 expect(redirectChain[2].url()).toContain('/non-existing-page-3.html');521 for (let i = 0; i < redirectChain.length; ++i) {522 const request = redirectChain[i];523 expect(request.isNavigationRequest()).toBe(true);524 expect(request.redirectChain().indexOf(request)).toBe(i);525 }526 });527 it('should work with redirects for subresources', async({page, server}) => {528 await page.setRequestInterception(true);529 const requests = [];530 page.on('request', request => {531 request.continue();532 if (!utils.isFavicon(request))533 requests.push(request);534 });535 server.setRedirect('/one-style.css', '/two-style.css');536 server.setRedirect('/two-style.css', '/three-style.css');537 server.setRedirect('/three-style.css', '/four-style.css');538 server.setRoute('/four-style.css', (req, res) => res.end('body {box-sizing: border-box; }'));539 const response = await page.goto(server.PREFIX + '/one-style.html');540 expect(response.status()).toBe(200);541 expect(response.url()).toContain('one-style.html');542 expect(requests.length).toBe(5);543 expect(requests[0].resourceType()).toBe('document');544 expect(requests[1].resourceType()).toBe('stylesheet');545 // Check redirect chain546 const redirectChain = requests[1].redirectChain();547 expect(redirectChain.length).toBe(3);548 expect(redirectChain[0].url()).toContain('/one-style.css');549 expect(redirectChain[2].url()).toContain('/three-style.css');550 });551 it('should be able to abort redirects', async({page, server}) => {552 await page.setRequestInterception(true);553 server.setRedirect('/non-existing.json', '/non-existing-2.json');554 server.setRedirect('/non-existing-2.json', '/simple.html');555 page.on('request', request => {556 if (request.url().includes('non-existing-2'))557 request.abort();558 else559 request.continue();560 });561 await page.goto(server.EMPTY_PAGE);562 const result = await page.evaluate(async() => {563 try {564 await fetch('/non-existing.json');565 } catch (e) {566 return e.message;567 }568 });569 if (CHROME)570 expect(result).toContain('Failed to fetch');571 else572 expect(result).toContain('NetworkError');573 });574 it('should work with equal requests', async({page, server}) => {575 await page.goto(server.EMPTY_PAGE);576 let responseCount = 1;577 server.setRoute('/zzz', (req, res) => res.end((responseCount++) * 11 + ''));578 await page.setRequestInterception(true);579 let spinner = false;580 // Cancel 2nd request.581 page.on('request', request => {582 if (utils.isFavicon(request)) {583 request.continue();584 return;585 }586 spinner ? request.abort() : request.continue();587 spinner = !spinner;588 });589 const results = await page.evaluate(() => Promise.all([590 fetch('/zzz').then(response => response.text()).catch(e => 'FAILED'),591 fetch('/zzz').then(response => response.text()).catch(e => 'FAILED'),592 fetch('/zzz').then(response => response.text()).catch(e => 'FAILED'),593 ]));594 expect(results).toEqual(['11', 'FAILED', '22']);595 });596 it_fails_ffox('should navigate to dataURL and fire dataURL requests', async({page, server}) => {597 await page.setRequestInterception(true);598 const requests = [];599 page.on('request', request => {600 requests.push(request);601 request.continue();602 });603 const dataURL = 'data:text/html,<div>yo</div>';604 const response = await page.goto(dataURL);605 expect(response.status()).toBe(200);606 expect(requests.length).toBe(1);607 expect(requests[0].url()).toBe(dataURL);608 });609 it_fails_ffox('should navigate to URL with hash and and fire requests without hash', async({page, server}) => {610 await page.setRequestInterception(true);611 const requests = [];612 page.on('request', request => {613 requests.push(request);614 request.continue();615 });616 const response = await page.goto(server.EMPTY_PAGE + '#hash');617 expect(response.status()).toBe(200);618 expect(response.url()).toBe(server.EMPTY_PAGE);619 expect(requests.length).toBe(1);620 expect(requests[0].url()).toBe(server.EMPTY_PAGE);621 });622 it('should work with encoded server', async({page, server}) => {623 // The requestWillBeSent will report encoded URL, whereas interception will624 // report URL as-is. @see crbug.com/759388625 await page.setRequestInterception(true);626 page.on('request', request => request.continue());627 const response = await page.goto(server.PREFIX + '/some nonexisting page');628 expect(response.status()).toBe(404);629 });630 it('should work with badly encoded server', async({page, server}) => {631 await page.setRequestInterception(true);632 server.setRoute('/malformed?rnd=%911', (req, res) => res.end());633 page.on('request', request => request.continue());634 const response = await page.goto(server.PREFIX + '/malformed?rnd=%911');635 expect(response.status()).toBe(200);636 });637 it_fails_ffox('should work with encoded server - 2', async({page, server}) => {638 // The requestWillBeSent will report URL as-is, whereas interception will639 // report encoded URL for stylesheet. @see crbug.com/759388640 await page.setRequestInterception(true);641 const requests = [];642 page.on('request', request => {643 request.continue();644 requests.push(request);645 });646 const response = await page.goto(`data:text/html,<link rel="stylesheet" href="${server.PREFIX}/fonts?helvetica|arial"/>`);647 expect(response.status()).toBe(200);648 expect(requests.length).toBe(2);649 expect(requests[1].response().status()).toBe(404);650 });651 it_fails_ffox('should not throw "Invalid Interception Id" if the request was cancelled', async({page, server}) => {652 await page.setContent('<iframe></iframe>');653 await page.setRequestInterception(true);654 let request = null;655 page.on('request', async r => request = r);656 page.$eval('iframe', (frame, url) => frame.src = url, server.EMPTY_PAGE),657 // Wait for request interception.658 await utils.waitEvent(page, 'request');659 // Delete frame to cause request to be canceled.660 await page.$eval('iframe', frame => frame.remove());661 let error = null;662 await request.continue().catch(e => error = e);663 expect(error).toBe(null);664 });665 it('should throw if interception is not enabled', async({page, server}) => {666 let error = null;667 page.on('request', async request => {668 try {669 await request.continue();670 } catch (e) {671 error = e;672 }673 });674 await page.goto(server.EMPTY_PAGE);675 expect(error.message).toContain('Request Interception is not enabled');676 });677 it_fails_ffox('should work with file URLs', async({page, server}) => {678 await page.setRequestInterception(true);679 const urls = new Set();680 page.on('request', request => {681 urls.add(request.url().split('/').pop());682 request.continue();683 });684 await page.goto(pathToFileURL(path.join(__dirname, 'assets', 'one-style.html')));685 expect(urls.size).toBe(2);686 expect(urls.has('one-style.html')).toBe(true);687 expect(urls.has('one-style.css')).toBe(true);688 });689 });690 describe('Request.continue', function() {691 it('should work', async({page, server}) => {692 await page.setRequestInterception(true);693 page.on('request', request => request.continue());694 await page.goto(server.EMPTY_PAGE);695 });696 it('should amend HTTP headers', async({page, server}) => {697 await page.setRequestInterception(true);698 page.on('request', request => {699 const headers = Object.assign({}, request.headers());700 headers['FOO'] = 'bar';701 request.continue({ headers });702 });703 await page.goto(server.EMPTY_PAGE);704 const [request] = await Promise.all([705 server.waitForRequest('/sleep.zzz'),706 page.evaluate(() => fetch('/sleep.zzz'))707 ]);708 expect(request.headers['foo']).toBe('bar');709 });710 it_fails_ffox('should redirect in a way non-observable to page', async({page, server}) => {711 await page.setRequestInterception(true);712 page.on('request', request => {713 const redirectURL = request.url().includes('/empty.html') ? server.PREFIX + '/consolelog.html' : undefined;714 request.continue({ url: redirectURL });715 });716 let consoleMessage = null;717 page.on('console', msg => consoleMessage = msg);718 await page.goto(server.EMPTY_PAGE);719 expect(page.url()).toBe(server.EMPTY_PAGE);720 expect(consoleMessage.text()).toBe('yellow');721 });722 it_fails_ffox('should amend method', async({page, server}) => {723 await page.goto(server.EMPTY_PAGE);724 await page.setRequestInterception(true);725 page.on('request', request => {726 request.continue({ method: 'POST' });727 });728 const [request] = await Promise.all([729 server.waitForRequest('/sleep.zzz'),730 page.evaluate(() => fetch('/sleep.zzz'))731 ]);732 expect(request.method).toBe('POST');733 });734 it_fails_ffox('should amend post data', async({page, server}) => {735 await page.goto(server.EMPTY_PAGE);736 await page.setRequestInterception(true);737 page.on('request', request => {738 request.continue({ postData: 'doggo' });739 });740 const [serverRequest] = await Promise.all([741 server.waitForRequest('/sleep.zzz'),742 page.evaluate(() => fetch('/sleep.zzz', { method: 'POST', body: 'birdy' }))743 ]);744 expect(await serverRequest.postBody).toBe('doggo');745 });746 });747 describe_fails_ffox('Request.respond', function() {748 it('should work', async({page, server}) => {749 await page.setRequestInterception(true);750 page.on('request', request => {751 request.respond({752 status: 201,753 headers: {754 foo: 'bar'755 },756 body: 'Yo, page!'757 });758 });759 const response = await page.goto(server.EMPTY_PAGE);760 expect(response.status()).toBe(201);761 expect(response.headers().foo).toBe('bar');762 expect(await page.evaluate(() => document.body.textContent)).toBe('Yo, page!');763 });764 it('should redirect', async({page, server}) => {765 await page.setRequestInterception(true);766 page.on('request', request => {767 if (!request.url().includes('rrredirect')) {768 request.continue();769 return;770 }771 request.respond({772 status: 302,773 headers: {774 location: server.EMPTY_PAGE,775 },776 });777 });778 const response = await page.goto(server.PREFIX + '/rrredirect');779 expect(response.request().redirectChain().length).toBe(1);780 expect(response.request().redirectChain()[0].url()).toBe(server.PREFIX + '/rrredirect');781 expect(response.url()).toBe(server.EMPTY_PAGE);782 });783 it('should allow mocking binary responses', async({page, server}) => {784 await page.setRequestInterception(true);785 page.on('request', request => {786 const imageBuffer = fs.readFileSync(path.join(__dirname, 'assets', 'pptr.png'));787 request.respond({788 contentType: 'image/png',789 body: imageBuffer790 });791 });792 await page.evaluate(PREFIX => {793 const img = document.createElement('img');794 img.src = PREFIX + '/does-not-exist.png';...

Full Screen

Full Screen

alerts_test.js

Source:alerts_test.js Github

copy

Full Screen

1// Copyright 2019 Google LLC2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14/**15 * @fileoverview Unit tests for alerts.js.16 */17goog.module('suspiciousSiteReporter.alerts.test');18goog.setTestOnly();19const alerts = goog.require('suspiciousSiteReporter.alerts');20describe('alerts', () => {21 beforeEach(() => {22 chrome.history = {23 search: jasmine.createSpy(),24 };25 jasmine.clock().mockDate(new Date(2019, 0, 1));26 chrome.history.search.and.callFake((details, callback) => {27 callback([28 {url: 'http://visitedyesterday.test/page1'},29 {url: 'http://visitedthreemonthsago.test/page1'},30 {31 url:32 'http://very-very-long-subdomain.many.many.subdomains.example.com'33 },34 ]);35 });36 });37 describe('isIDN', () => {38 it('should return false when site does not use an IDN', () => {39 expect(alerts.isIDN('not-idn.com')).toEqual(false);40 expect(alerts.isIDN('some-xn--com')).toEqual(false);41 expect(alerts.isIDN('test.some-xn--com')).toEqual(false);42 expect(alerts.isIDN('test.com/xn--v8j0cwa6g')).toEqual(false);43 });44 it('should return true when site uses an IDN', () => {45 // Uses ひらがな.com, which should be encoded before getting46 // passed into this function.47 expect(alerts.isIDN('xn--v8j0cwa6g.com/')).toEqual(true);48 expect(alerts.isIDN('test.xn--v8j0cwa6g.com/')).toEqual(true);49 expect(alerts.isIDN('xn--v8j0cwa6g.com')).toEqual(true);50 expect(alerts.isIDN('test.xn--com')).toEqual(true);51 });52 });53 // These tests assume that chrome.history.search is getting called with the54 // correct arguments.55 describe('visitedBeforeToday', () => {56 it('should return false when site visited for the first time today',57 (done) => {58 alerts.visitedBeforeToday('visitedtoday.test').then((response) => {59 expect(response).toEqual(false);60 done();61 });62 });63 it('should return false when site visited over six months ago', (done) => {64 alerts.visitedBeforeToday('visitedoneyearago.test').then((response) => {65 expect(response).toEqual(false);66 done();67 });68 });69 it('should return true when site visited yesterday', (done) => {70 alerts.visitedBeforeToday('visitedyesterday.test').then((response) => {71 expect(response).toEqual(true);72 done();73 });74 });75 it('should return true when site visited three months ago', (done) => {76 alerts.visitedBeforeToday('visitedthreemonthsago.test')77 .then((response) => {78 expect(response).toEqual(true);79 done();80 });81 });82 it('should return true when the user has no browsing history', (done) => {83 chrome.history.search = jasmine.createSpy();84 chrome.history.search.and.callFake((details, callback) => {85 callback([]);86 });87 alerts.visitedBeforeToday('').then((response) => {88 expect(response).toEqual(true);89 done();90 });91 });92 });93 describe('hasLongSubdomains', () => {94 it('should return true when site has unusually long subdomains', () => {95 expect(alerts.hasLongSubdomains('very-very-long-subdomain.example.co.uk'))96 .toEqual(true);97 expect(alerts.hasLongSubdomains(98 'very.com.very-very-long-subdomain.example.com'))99 .toEqual(true);100 });101 it('should return false when site does not have unusually long subdomains',102 () => {103 expect(alerts.hasLongSubdomains('short-subdomain.example.co.uk'))104 .toEqual(false);105 });106 });107 describe('hasManySubdomains', () => {108 it('should return true when site has unusually many subdomains', () => {109 expect(alerts.hasManySubdomains('many.many.many.subdomains.co.uk'))110 .toEqual(true);111 expect(alerts.hasManySubdomains('many.many.many.subdomains.com'))112 .toEqual(true);113 });114 it('should return false when site does not have unusually many subdomains',115 () => {116 expect(alerts.hasManySubdomains('not-many.subdomains.co.uk'))117 .toEqual(false);118 expect(alerts.hasManySubdomains('not-many.subdomains.com'))119 .toEqual(false);120 });121 });122 describe('hasMultipleUrlShortenerRedirects', () => {123 it('should return true when the site has more than one redirect through a ' +124 'URL shortener',125 () => {126 const redirectUrls = new Set([127 'http://goo.gl/test', 'https://goo.gl/test',128 'https://goo.gl/redirect-test'129 ]);130 expect(alerts.hasMultipleUrlShortenerRedirects(redirectUrls))131 .toEqual(true);132 });133 it('should return false when the site has one redirect through a URL ' +134 'shortener',135 () => {136 const redirectUrls = new Set([137 'http://goo.gl/test', 'https://goo.gl/test',138 'https://redirect-test.com'139 ]);140 expect(alerts.hasMultipleUrlShortenerRedirects(redirectUrls))141 .toEqual(false);142 });143 });144 describe('redirectsThroughSuspiciousTld', () => {145 it('should return true when redirects through a suspicious TLD', () => {146 const redirectUrls = new Set(['https://test.stream', 'https://test.com']);147 expect(alerts.redirectsThroughSuspiciousTld(redirectUrls)).toEqual(true);148 });149 it('should return false when the site does not redirect through a ' +150 'suspicious TLD',151 () => {152 const redirectUrls = new Set(['http://test.com', 'https://test.com']);153 expect(alerts.redirectsThroughSuspiciousTld(redirectUrls))154 .toEqual(false);155 });156 });157 describe('redirectsFromOutsideProgramOrWebmail', () => {158 it('should return true when the redirect is initiated from outside program',159 () => {160 const redirectChain = [161 {162 urlType: 'CLIENT_REDIRECT',163 referrerUrl: 'https://test.com',164 },165 {166 urlType: 'CLIENT_REDIRECT',167 referrerUrl: 'https://outside-program.test',168 maybeLaunchedByExternalApp: true,169 },170 ];171 expect(alerts.redirectsFromOutsideProgramOrWebmail(redirectChain))172 .toEqual(true);173 });174 it('should return true when the redirect is initiated from webmail', () => {175 const redirectChain = [176 {177 urlType: 'CLIENT_REDIRECT',178 referrerUrl: 'https://test.com',179 },180 {181 urlType: 'CLIENT_REDIRECT',182 referrerUrl: 'https://test.mail.google.com',183 },184 ];185 expect(alerts.redirectsFromOutsideProgramOrWebmail(redirectChain))186 .toEqual(true);187 });188 it('should return false when the redirect is not initiated from outside' +189 'program or webmail',190 () => {191 const redirectChain = [192 {193 urlType: 'CLIENT_REDIRECT',194 referrerUrl: 'https://test.com',195 },196 {197 urlType: 'CLIENT_REDIRECT',198 referrerUrl: 'https://example.test',199 },200 ];201 expect(alerts.redirectsFromOutsideProgramOrWebmail(redirectChain))202 .toEqual(false);203 });204 it('should return false when the redirect chain is empty',205 () => {206 const redirectChain = [];207 expect(alerts.redirectsFromOutsideProgramOrWebmail(redirectChain))208 .toEqual(false);209 });210 });211 describe('redirect chain', () => {212 const referrerChain = [213 {214 urlType: 'CLIENT_REDIRECT',215 referrerUrl: 'test.com',216 serverRedirectChain:217 [{url: 'url-shortener.test'}, {url: 'redirect-test.com'}],218 },219 {220 urlType: 'LANDING_PAGE',221 referrerUrl: 'test.com',222 },223 {224 urlType: 'RECENT_NAVIGATION',225 referrerUrl: 'example-test.com',226 },227 ];228 const redirectChain = referrerChain.slice(0, 1);229 describe('getRedirectUrls', () => {230 it('should return client and server redirect URLs from the referrer',231 () => {232 expect(alerts.getRedirectUrls(redirectChain)).toEqual(new Set([233 'test.com', 'url-shortener.test', 'redirect-test.com'234 ]));235 });236 });237 describe('fetchRedirectChain', () => {238 it('should return only the relevant redirect entries', (done) => {239 chrome.safeBrowsingPrivate = {240 getReferrerChain: jasmine.createSpy(),241 };242 chrome.safeBrowsingPrivate.getReferrerChain.and.callFake(243 (tabId, callback) => {244 callback(referrerChain);245 });246 alerts.fetchRedirectChain('redirect-test.com', /* tabId= */ 123)247 .then((response) => {248 expect(response).toEqual(redirectChain);249 done();250 });251 });252 });253 });254 describe('computeAlerts', () => {255 // For this test case, the redirect and top site alerts will fire256 // due to mock setup complexity, while the remaining alerts trigger as257 // expected based on the URL passed into the computeAlerts function258 // and setup in the beforeEach at the top of this file.259 it('should return the correct list of alerts', async (done) => {260 alerts261 .computeAlerts(262 'http://very-very-long-subdomain.many.many.subdomains.example.com',263 /* tabId= */ 123)264 .then((response) => {265 expect(response.length).toEqual(2);266 expect(response).toContain(alerts.ALERT_MESSAGES['longSubdomains']);267 expect(response).toContain(alerts.ALERT_MESSAGES['manySubdomains']);268 });269 alerts270 .computeAlerts(271 'http://new-few-very-long-subdomain.example.com',272 /* tabId= */ 123)273 .then((response) => {274 expect(response.length).toEqual(2);275 expect(response).toContain(alerts.ALERT_MESSAGES['longSubdomains']);276 expect(response).toContain(277 alerts.ALERT_MESSAGES['notVisitedBefore']);278 });279 done();280 });281 });...

Full Screen

Full Screen

NetworkManager.js

Source:NetworkManager.js Github

copy

Full Screen

...163 }164 headers() {165 return {...this._headers};166 }167 redirectChain() {168 return this._redirectChain.slice();169 }170 resourceType() {171 return this._resourceType;172 }173 url() {174 return this._url;175 }176 method() {177 return this._method;178 }179 isNavigationRequest() {180 return this._isNavigationRequest;181 }...

Full Screen

Full Screen

handler.js

Source:handler.js Github

copy

Full Screen

...69 model.info.onRequest(page.requests[rid], request, context);70 }71 }72 // REDIRECTIONS73 const redirectChain = request.redirectChain();74 if (redirectChain.length > 0) {75 let index = redirectChain.indexOf(request);76 index = index === -1 ? redirectChain.length : index;77 let firstRequest = redirectChain[0];78 let prevRequest = redirectChain[index - 1];79 let prid = requestId(prevRequest);80 page.requests[rid].prevId = prid;81 page.requests[rid].sourceId = requestId(firstRequest);82 if (!page.requests[prid])83 page.requests[prid] = requestInfo(request, page);84 page.requests[prid].nextId = rid;85 }86 };87 const onReponseHandler = async response => {...

Full Screen

Full Screen

file_loadinfo_redirectchain.sjs

Source:file_loadinfo_redirectchain.sjs Github

copy

Full Screen

1/*2 * Redirect handler specifically for the needs of:3 * Bug 1194052 - Append Principal to RedirectChain within LoadInfo before the channel is succesfully openend4 */5function createIframeContent(aQuery) {6 var content =`7 <!DOCTYPE HTML>8 <html>9 <head><meta charset="utf-8">10 <title>Bug 1194052 - LoadInfo redirect chain subtest</title>11 </head>12 <body>13 <script type="text/javascript">14 var myXHR = new XMLHttpRequest();15 myXHR.open("GET", "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?` + aQuery + `");16 myXHR.onload = function() {17 var loadinfo = SpecialPowers.wrap(myXHR).channel.loadInfo;18 var redirectChain = loadinfo.redirectChain;19 var redirectChainIncludingInternalRedirects = loadinfo.redirectChainIncludingInternalRedirects;20 var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };21 for (var i = 0; i < redirectChain.length; i++) {22 resultOBJ.redirectChain.push(redirectChain[i].URI.spec);23 }24 for (var i = 0; i < redirectChainIncludingInternalRedirects.length; i++) {25 resultOBJ.redirectChainIncludingInternalRedirects.push(redirectChainIncludingInternalRedirects[i].URI.spec);26 }27 var loadinfoJSON = JSON.stringify(resultOBJ);28 window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");29 }30 myXHR.onerror = function() {31 var resultOBJ = { redirectChain : [], redirectChainIncludingInternalRedirects : [] };32 var loadinfoJSON = JSON.stringify(resultOBJ);33 window.parent.postMessage({ loadinfo: loadinfoJSON }, "*");34 }35 myXHR.send();36 </script>37 </body>38 </html>`;39 return content;40}41function handleRequest(request, response)42{43 response.setHeader("Cache-Control", "no-cache", false);44 var queryString = request.queryString;45 if (queryString == "iframe-redir-https-2" ||46 queryString == "iframe-redir-err-2") {47 var query = queryString.replace("iframe-", "");48 // send upgrade-insecure-requests CSP header49 response.setHeader("Content-Type", "text/html", false);50 response.setHeader("Content-Security-Policy", "upgrade-insecure-requests", false);51 response.write(createIframeContent(query));52 return;53 }54 // at the end of the redirectchain we return some text55 // for sanity checking56 if (queryString == "redir-0" ||57 queryString == "redir-https-0") {58 response.setHeader("Content-Type", "text/html", false);59 response.write("checking redirectchain");60 return;61 }62 // special case redir-err-1 and return an error to trigger the fallback63 if (queryString == "redir-err-1") {64 response.setStatusLine("1.1", 404, "Bad request");65 return;66 }67 // must be a redirect68 var newLoaction = "";69 switch (queryString) {70 case "redir-err-2":71 newLocation =72 "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-err-1";73 break;74 case "redir-https-2":75 newLocation =76 "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-1";77 break;78 case "redir-https-1":79 newLocation =80 "http://example.com/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-https-0";81 break;82 case "redir-2":83 newLocation =84 "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-1";85 break;86 case "redir-1":87 newLocation =88 "http://mochi.test:8888/tests/netwerk/test/mochitests/file_loadinfo_redirectchain.sjs?redir-0";89 break;90 }91 response.setStatusLine("1.1", 302, "Found");92 response.setHeader("Location", newLocation, false);...

Full Screen

Full Screen

index.js

Source:index.js Github

copy

Full Screen

1/**2 * External dependencies3 */4import { parse } from 'url';5/**6 * Internal dependencies7 */8import {9 hasRenewalItem,10 getRenewalItems,11 hasDomainRegistration,12 hasDomainMapping,13 hasProduct,14} from 'lib/cart-values/cart-items';15import { managePurchase } from 'me/purchases/paths';16import {17 UPGRADE_INTENT_PLUGINS,18 UPGRADE_INTENT_INSTALL_PLUGIN,19 UPGRADE_INTENT_THEMES,20 UPGRADE_INTENT_INSTALL_THEME,21} from 'lib/checkout/constants';22import { decodeURIComponentIfValid, isExternal } from 'lib/url';23import { domainManagementEdit } from '../../my-sites/domains/paths';24import { isDomainRegistration } from '../products-values';25const isValidValue = ( url ) => typeof url === 'string' && url;26export function isValidUpgradeIntent( upgradeIntent ) {27 switch ( upgradeIntent ) {28 case UPGRADE_INTENT_PLUGINS:29 case UPGRADE_INTENT_INSTALL_PLUGIN:30 case UPGRADE_INTENT_THEMES:31 case UPGRADE_INTENT_INSTALL_THEME:32 return true;33 }34 return false;35}36export function parseRedirectToChain( rawUrl, includeOriginalUrl = true ) {37 const redirectChain = [];38 const url = decodeURIComponentIfValid( rawUrl );39 if ( includeOriginalUrl && isValidValue( url ) ) {40 redirectChain.push( url );41 }42 const parseUrlAndPushToChain = ( currentUrl ) => {43 const {44 query: { redirect_to },45 } = parse( currentUrl, true );46 if ( isValidValue( redirect_to ) ) {47 redirectChain.push( redirect_to );48 parseUrlAndPushToChain( decodeURIComponentIfValid( redirect_to ) );49 }50 };51 parseUrlAndPushToChain( url );52 return redirectChain;53}54export function getValidDeepRedirectTo( redirectTo ) {55 const redirectChain = parseRedirectToChain( redirectTo );56 if (57 Array.isArray( redirectChain ) &&58 redirectChain.length &&59 ! isExternal( redirectChain[ redirectChain.length - 1 ] )60 ) {61 return redirectChain[ redirectChain.length - 1 ];62 }63}64export function getExitCheckoutUrl(65 cart,66 siteSlug,67 upgradeIntent,68 redirectTo,69 returnToBlockEditor,70 returnToHome,71 previousPath72) {73 let url = '/plans/';74 if ( returnToBlockEditor ) {75 return `/block-editor/page/${ siteSlug }/home`;76 }77 if ( returnToHome ) {78 return `/home/${ siteSlug }`;79 }80 if ( hasRenewalItem( cart ) ) {81 const firstRenewalItem = getRenewalItems( cart )[ 0 ];82 const { purchaseId, purchaseDomain } = firstRenewalItem.extra,83 siteName = siteSlug || purchaseDomain;84 if ( isDomainRegistration( firstRenewalItem ) ) {85 const domainManagementPage = domainManagementEdit( siteName, firstRenewalItem.meta );86 if ( previousPath && previousPath.startsWith( domainManagementPage ) ) {87 return domainManagementPage;88 }89 }90 return managePurchase( siteName, purchaseId );91 }92 if ( isValidUpgradeIntent( upgradeIntent ) ) {93 const finalRedirectTo = getValidDeepRedirectTo( redirectTo );94 if ( finalRedirectTo ) {95 return finalRedirectTo;96 }97 }98 if ( hasDomainRegistration( cart ) ) {99 url = '/domains/add/';100 } else if ( hasDomainMapping( cart ) ) {101 url = '/domains/add/mapping/';102 } else if ( hasProduct( cart, 'offsite_redirect' ) ) {103 url = '/domains/add/site-redirect/';104 } else if ( hasProduct( cart, 'premium_theme' ) ) {105 url = '/themes/';106 }107 return siteSlug ? url + siteSlug : url;108}109export { getCreditCardType, validatePaymentDetails } from './validation';...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1(async () => {2 const browser = await puppeteer.launch();3 const page = await browser.newPage();4 const chain = await page.redirectChain();5 console.log(chain);6 await browser.close();7})();8(async () => {9 const browser = await chromium.launch();10 const context = await browser.newContext();11 const page = await context.newPage();12 const chain = await page.redirectChain();13 console.log(chain);14 await browser.close();15})();16(async () => {17 const driver = await new Builder().forBrowser('chrome').build();18 const chain = await driver.navigate().redirectChain();19 console.log(chain);20 await driver.quit();21})();22(async () => {23 const browser = await remote({24 capabilities: {25 }26 })27 const chain = await browser.getRedirectChain()28 console.log(chain)29 await browser.deleteSession()30})()31describe('Test to check redirectChain method', function() {32 it('Visit example.com', function() {33 cy.getRedirectChain().should('deep.equal', [34 })35})36test('My first test', async t => {

Full Screen

Using AI Code Generation

copy

Full Screen

1const puppeteer = require('puppeteer');2(async () => {3 const browser = await puppeteer.launch();4 const page = await browser.newPage();5 const chain = await page.redirectChain();6 console.log(chain);7 await browser.close();8})();9 {10 headers: {11 'content-type': 'text/html; charset=ISO-8859-1',12 }13 }14const puppeteer = require('puppeteer');15(async () => {16 const browser = await puppeteer.launch();17 const page = await browser.newPage();18 const chain = await page.redirectChain();19 console.log(chain);20 await browser.close();21})();22 {23 headers: {24 'content-type': 'text/html; charset=ISO-8859-1',25 }26 },27 {28 headers: {

Full Screen

Using AI Code Generation

copy

Full Screen

1(async () => {2 const browser = await puppeteer.launch();3 const page = await browser.newPage();4 const redirectChain = await page.redirectChain();5 console.log(redirectChain);6 await browser.close();7})();8(async () => {9 const browser = await puppeteer.launch();10 const page = await browser.newPage();11 const response = await page.waitForNavigation();12 console.log(response.url());13 await browser.close();14})();15(async () => {16 const browser = await puppeteer.launch();17 const page = await browser.newPage();18 await page.waitForNavigation({ waitUntil: 'networkidle0' });19 await page.screenshot({ path: 'google.png' });20 await browser.close();21})();22(async () => {23 const browser = await puppeteer.launch();24 const page = await browser.newPage();25 await page.waitForNavigation({ waitUntil: 'networkidle0' });26 await page.pdf({ path: 'google.pdf' });27 await browser.close();28})();29(async () => {30 const browser = await puppeteer.launch();31 const page = await browser.newPage();32 await page.waitForNavigation({ waitUntil: 'networkidle0' });33 await page.pdf({ path: 'google.pdf' });34 await browser.close();35})();36(async () => {37 const browser = await puppeteer.launch();38 const page = await browser.newPage();39 await page.waitForNavigation({ waitUntil: 'network

Full Screen

Using AI Code Generation

copy

Full Screen

1const puppeteer = require('puppeteer');2const url = require('url');3(async () => {4 const browser = await puppeteer.launch();5 const page = await browser.newPage();6 const redirectChain = await page.redirectChain();7 redirectChain.forEach(response => {8 console.log(url.parse(response.url()).hostname);9 });10 await browser.close();11})();

Full Screen

Using AI Code Generation

copy

Full Screen

1const puppeteer = require('puppeteer');2(async () => {3 const browser = await puppeteer.launch();4 const page = await browser.newPage();5 console.log(response.request().redirectChain());6 console.log(response.request().redirectChain().length);7 await browser.close();8})();9const puppeteer = require('puppeteer');10(async () => {11 const browser = await puppeteer.launch();12 const page = await browser.newPage();13 console.log(response.request().redirectChain());14 console.log(response.request().redirectChain().length);15 await browser.close();16})();17const puppeteer = require('puppeteer');18(async () => {19 const browser = await puppeteer.launch();20 const page = await browser.newPage();21 console.log(response.request().redirectChain());22 console.log(response.request().redirectChain().length);23 await browser.close();24})();25const puppeteer = require('puppeteer');26(async () => {27 const browser = await puppeteer.launch();28 const page = await browser.newPage();29 console.log(response.request().redirectChain());30 console.log(response.request().redirectChain().length);31 await browser.close();32})();33const puppeteer = require('puppeteer');

Full Screen

Using AI Code Generation

copy

Full Screen

1const puppeteer = require('puppeteer');2(async () => {3 const browser = await puppeteer.launch();4 const page = await browser.newPage();5 const chain = await page.redirectChain();6 console.log(chain);7 await browser.close();8})();

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Puppeteer 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