Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  evaluation.spec.ts   Sprache: unbekannt

 
/**
 * @license
 * Copyright 2018 Google Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

import expect from 'expect';

import {getTestState, setupTestBrowserHooks} from './mocha-utils.js';
import {attachFrame} from './utils.js';

describe('Evaluation specs', function () {
  setupTestBrowserHooks();

  describe('Page.evaluate', function () {
    it('should work', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return 7 * 3;
      });
      expect(result).toBe(21);
    });
    it('should transfer BigInt', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate((a: bigint) => {
        return a;
      }, BigInt(42));
      expect(result).toBe(BigInt(42));
    });
    it('should transfer NaN', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(a => {
        return a;
      }, NaN);
      expect(Object.is(result, NaN)).toBe(true);
    });
    it('should transfer -0', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(a => {
        return a;
      }, -0);
      expect(Object.is(result, -0)).toBe(true);
    });
    it('should transfer Infinity', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(a => {
        return a;
      }, Infinity);
      expect(Object.is(result, Infinity)).toBe(true);
    });
    it('should transfer -Infinity', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(a => {
        return a;
      }, -Infinity);
      expect(Object.is(result, -Infinity)).toBe(true);
    });
    it('should transfer arrays', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(
        a => {
          return a;
        },
        [1, 2, 3],
      );
      expect(result).toEqual([1, 2, 3]);
    });
    it('should transfer arrays as arrays, not objects', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(
        a => {
          return Array.isArray(a);
        },
        [1, 2, 3],
      );
      expect(result).toBe(true);
    });
    it('should modify global environment', async () => {
      const {page} = await getTestState();

      await page.evaluate(() => {
        return ((globalThis as any).globalVar = 123);
      });
      expect(await page.evaluate('globalVar')).toBe(123);
    });
    it('should evaluate in the page context', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.PREFIX + '/global-var.html');
      expect(await page.evaluate('globalVar')).toBe(123);
    });
    it('should replace symbols with undefined', async () => {
      const {page} = await getTestState();

      expect(
        await page.evaluate(() => {
          return [Symbol('foo4'), 'foo'];
        }),
      ).toEqual([undefined, 'foo']);
    });
    it('should work with function shorthands', async () => {
      const {page} = await getTestState();

      const a = {
        sum(a: number, b: number) {
          return a + b;
        },

        async mult(a: number, b: number) {
          return a * b;
        },
      };
      expect(await page.evaluate(a.sum, 1, 2)).toBe(3);
      expect(await page.evaluate(a.mult, 2, 4)).toBe(8);
    });
    it('should work with unicode chars', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(
        a => {
          return a['中文字符'];
        },
        {
          中文字符: 42,
        },
      );
      expect(result).toBe(42);
    });
    it('should throw when evaluation triggers reload', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page
        .evaluate(() => {
          location.reload();
          return new Promise(() => {});
        })
        .catch(error_ => {
          return (error = error_);
        });
      expect(error.message).toContain('Protocol error');
    });
    it('should await promise', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return Promise.resolve(8 * 7);
      });
      expect(result).toBe(56);
    });
    it('should work right after framenavigated', async () => {
      const {page, server} = await getTestState();

      let frameEvaluation = null;
      page.on('framenavigated', async frame => {
        frameEvaluation = frame.evaluate(() => {
          return 6 * 7;
        });
      });
      await page.goto(server.EMPTY_PAGE);
      expect(await frameEvaluation).toBe(42);
    });
    it('should work from-inside an exposed function', async () => {
      const {page} = await getTestState();

      // Setup inpage callback, which calls Page.evaluate
      await page.exposeFunction(
        'callController',
        async function (a: number, b: number) {
          return await page.evaluate(
            (a: number, b: number): number => {
              return a * b;
            },
            a,
            b,
          );
        },
      );
      const result = await page.evaluate(async function () {
        return (globalThis as any).callController(9, 3);
      });
      expect(result).toBe(27);
    });
    it('should reject promise with exception', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page
        .evaluate(() => {
          // @ts-expect-error we know the object doesn't exist
          return notExistingObject.property;
        })
        .catch(error_ => {
          return (error = error_);
        });
      expect(error).toBeTruthy();
      expect(error.message).toContain('notExistingObject');
    });
    it('should support thrown strings as error messages', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page
        .evaluate(() => {
          throw 'qwerty';
        })
        .catch(error_ => {
          return (error = error_);
        });
      expect(error).toEqual('qwerty');
    });
    it('should support thrown numbers as error messages', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page
        .evaluate(() => {
          throw 100500;
        })
        .catch(error_ => {
          return (error = error_);
        });
      expect(error).toEqual(100500);
    });
    it('should return complex objects', async () => {
      const {page} = await getTestState();

      const object = {foo: 'bar!'};
      const result = await page.evaluate(a => {
        return a;
      }, object);
      expect(result).not.toBe(object);
      expect(result).toEqual(object);
    });
    it('should return BigInt', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return BigInt(42);
      });
      expect(result).toBe(BigInt(42));
    });
    it('should return NaN', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return NaN;
      });
      expect(Object.is(result, NaN)).toBe(true);
    });
    it('should return -0', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return -0;
      });
      expect(Object.is(result, -0)).toBe(true);
    });
    it('should return Infinity', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return Infinity;
      });
      expect(Object.is(result, Infinity)).toBe(true);
    });
    it('should return -Infinity', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return -Infinity;
      });
      expect(Object.is(result, -Infinity)).toBe(true);
    });
    it('should accept "null" as one of multiple parameters', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(
        (a, b) => {
          return Object.is(a, null) && Object.is(b, 'foo');
        },
        null,
        'foo',
      );
      expect(result).toBe(true);
    });
    it('should properly serialize null fields', async () => {
      const {page} = await getTestState();

      expect(
        await page.evaluate(() => {
          return {a: undefined};
        }),
      ).toEqual({});
    });
    it('should return undefined for non-serializable objects', async () => {
      const {page} = await getTestState();

      expect(
        await page.evaluate(() => {
          return window;
        }),
      ).toBe(undefined);
    });
    it('should return promise as empty object', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        return {
          promise: new Promise(resolve => {
            setTimeout(resolve, 1000);
          }),
        };
      });
      expect(result).toEqual({
        promise: {},
      });
    });
    it('should work for circular object', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        const a: Record<string, unknown> = {
          c: 5,
          d: {
            foo: 'bar',
          },
        };
        const b = {a};
        a['b'] = b;
        return a;
      });
      expect(result).toMatchObject({
        c: 5,
        d: {
          foo: 'bar',
        },
        b: {
          a: undefined,
        },
      });
    });
    it('should accept a string', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate('1 + 2');
      expect(result).toBe(3);
    });
    it('should accept a string with semi colons', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate('1 + 5;');
      expect(result).toBe(6);
    });
    it('should accept a string with comments', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate('2 + 5;\n// do some math!');
      expect(result).toBe(7);
    });
    it('should accept element handle as an argument', async () => {
      const {page} = await getTestState();

      await page.setContent('<section>42</section>');
      using element = (await page.$('section'))!;
      const text = await page.evaluate(e => {
        return e.textContent;
      }, element);
      expect(text).toBe('42');
    });
    it('should throw if underlying element was disposed', async () => {
      const {page} = await getTestState();

      await page.setContent('<section>39</section>');
      using element = (await page.$('section'))!;
      expect(element).toBeTruthy();
      // We want to dispose early.
      await element.dispose();
      let error!: Error;
      await page
        .evaluate(e => {
          return e.textContent;
        }, element)
        .catch(error_ => {
          return (error = error_);
        });
      expect(error.message).toContain('JSHandle is disposed');
    });
    it('should throw if elementHandles are from other frames', async () => {
      const {page, server} = await getTestState();

      await attachFrame(page, 'frame1', server.EMPTY_PAGE);
      using bodyHandle = await page.frames()[1]!.$('body');
      let error!: Error;
      await page
        .evaluate(body => {
          return body?.innerHTML;
        }, bodyHandle)
        .catch(error_ => {
          return (error = error_);
        });
      expect(error).toBeTruthy();
      expect(error.message).atLeastOneToContain([
        'JSHandles can be evaluated only in the context they were created',
        "Trying to evaluate JSHandle from different frames. Usually this means you're using a handle from a page on a different page.",
      ]);
    });
    it('should simulate a user gesture', async () => {
      const {page} = await getTestState();

      const result = await page.evaluate(() => {
        document.body.appendChild(document.createTextNode('test'));
        document.execCommand('selectAll');
        return document.execCommand('copy');
      });
      expect(result).toBe(true);
    });
    it('should not throw an error when evaluation does a navigation', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.PREFIX + '/one-style.html');
      const onRequest = server.waitForRequest('/empty.html');
      const result = await page.evaluate(() => {
        (window as any).location = '/empty.html';
        return [42];
      });
      expect(result).toEqual([42]);
      await onRequest;
    });
    it('should transfer 100Mb of data from page to node.js', async function () {
      this.timeout(25_000);
      const {page} = await getTestState();

      const a = await page.evaluate(() => {
        return Array(100 * 1024 * 1024 + 1).join('a');
      });
      expect(a.length).toBe(100 * 1024 * 1024);
    });
    it('should throw error with detailed information on exception inside promise', async () => {
      const {page} = await getTestState();

      let error!: Error;
      await page
        .evaluate(() => {
          return new Promise(() => {
            throw new Error('Error in promise');
          });
        })
        .catch(error_ => {
          return (error = error_);
        });
      expect(error.message).toContain('Error in promise');
    });

    it('should return properly serialize objects with unknown type fields', async () => {
      const {page} = await getTestState();
      await page.setContent(
        "<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='>",
      );

      const result = await page.evaluate(async () => {
        const image = document.querySelector('img')!;
        const imageBitmap = await createImageBitmap(image);

        return {
          a: 'foo',
          b: imageBitmap,
        };
      });

      expect(result).toEqual({
        a: 'foo',
        b: undefined,
      });
    });
  });

  describe('Page.evaluateOnNewDocument', function () {
    it('should evaluate before anything else on the page', async () => {
      const {page, server} = await getTestState();

      await page.evaluateOnNewDocument(function () {
        (globalThis as any).injected = 123;
      });
      await page.goto(server.PREFIX + '/tamperable.html');
      expect(
        await page.evaluate(() => {
          return (globalThis as any).result;
        }),
      ).toBe(123);
    });
    it('should work with CSP', async () => {
      const {page, server} = await getTestState();

      server.setCSP('/empty.html', 'script-src ' + server.PREFIX);
      await page.evaluateOnNewDocument(function () {
        (globalThis as any).injected = 123;
      });
      await page.goto(server.PREFIX + '/empty.html');
      expect(
        await page.evaluate(() => {
          return (globalThis as any).injected;
        }),
      ).toBe(123);

      // Make sure CSP works.
      await page.addScriptTag({content: 'window.e = 10;'}).catch(error => {
        return void error;
      });
      expect(
        await page.evaluate(() => {
          return (window as any).e;
        }),
      ).toBe(undefined);
    });
  });

  describe('Page.removeScriptToEvaluateOnNewDocument', function () {
    it('should remove new document script', async () => {
      const {page, server} = await getTestState();

      const {identifier} = await page.evaluateOnNewDocument(function () {
        (globalThis as any).injected = 123;
      });
      await page.goto(server.PREFIX + '/tamperable.html');
      expect(
        await page.evaluate(() => {
          return (globalThis as any).result;
        }),
      ).toBe(123);

      await page.removeScriptToEvaluateOnNewDocument(identifier);
      await page.reload();
      expect(
        await page.evaluate(() => {
          return (globalThis as any).result || null;
        }),
      ).toBe(null);
    });
  });

  describe('Frame.evaluate', function () {
    it('should have different execution contexts', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.EMPTY_PAGE);
      await attachFrame(page, 'frame1', server.EMPTY_PAGE);
      expect(page.frames()).toHaveLength(2);
      await page.frames()[0]!.evaluate(() => {
        return ((globalThis as any).FOO = 'foo');
      });
      await page.frames()[1]!.evaluate(() => {
        return ((globalThis as any).FOO = 'bar');
      });
      expect(
        await page.frames()[0]!.evaluate(() => {
          return (globalThis as any).FOO;
        }),
      ).toBe('foo');
      expect(
        await page.frames()[1]!.evaluate(() => {
          return (globalThis as any).FOO;
        }),
      ).toBe('bar');
    });
    it('should have correct execution contexts', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.PREFIX + '/frames/one-frame.html');
      expect(page.frames()).toHaveLength(2);
      expect(
        await page.frames()[0]!.evaluate(() => {
          return document.body.textContent!.trim();
        }),
      ).toBe('');
      expect(
        await page.frames()[1]!.evaluate(() => {
          return document.body.textContent!.trim();
        }),
      ).toBe(`Hi, I'm frame`);
    });
    it('should execute after cross-site navigation', async () => {
      const {page, server} = await getTestState();

      await page.goto(server.EMPTY_PAGE);
      const mainFrame = page.mainFrame();
      expect(
        await mainFrame.evaluate(() => {
          return window.location.href;
        }),
      ).toContain('localhost');
      await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
      expect(
        await mainFrame.evaluate(() => {
          return window.location.href;
        }),
      ).toContain('127');
    });
  });
});

[ Dauer der Verarbeitung: 0.35 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge