<commit_before>'use strict';

/* eslint-env mocha */
/* eslint-disable func-names, prefer-arrow-callback */

const fs = require('fs');
const IcalExpander = require('../');
const assert = require('assert');
const path = require('path');

// NOTE: Run with TZ=Etc/UTC mocha ical-parser.js
// https://github.com/mozilla-comm/ical.js/issues/257

const icaljsIssue257 = fs.readFileSync(path.join(__dirname, 'icaljs-issue-257.ics'), 'utf-8');
const icaljsIssue285 = fs.readFileSync(path.join(__dirname, 'icaljs-issue-285.ics'), 'utf-8');
const recurIcs = fs.readFileSync(path.join(__dirname, 'recur.ics'), 'utf-8');
const invalidDates = fs.readFileSync(path.join(__dirname, 'invalid_dates.ics'), 'utf-8');
const betweenTestCalendar = fs.readFileSync(path.join(__dirname, 'between_dates.ics'), 'utf-8');
const allDayEventCalendar = fs.readFileSync(path.join(__dirname, 'all-day.ics'), 'utf-8');

it('should show first date', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-07-24T00:00:00.000Z'), new Date('2016-07-26T00:00:00.000Z'));

  assert.equal(events.events[0].summary, 'Test-Event');
  assert.equal(events.occurrences.length, 0);
});

it('should show recurring modified date', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-07-31T00:00:00.000Z'), new Date('2016-08-02T00:00:00.000Z'));

  assert.equal(events.events[0].summary, 'Test-Event - Reccurence #2');
  assert.equal(events.occurrences.length, 0);
});

it('should show nothing at recurring exdate', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-08-07T00:00:00.000Z'), new Date('2016-08-10T00:00:00.000Z'));

  assert.equal(events.events.length, 0);
  assert.equal(events.occurrences.length, 0);
});

it('should parse issue 285 case correctly', function () {
  const events = new IcalExpander({ ics: icaljsIssue285 })
    .between(new Date('2017-01-03T00:00:00.000Z'), new Date('2017-01-25T00:00:00.000Z'));

  const allEvents = events.events.concat(events.occurrences);
  assert.deepEqual(allEvents.map(e => e.startDate.toJSDate().toISOString()), [
    '2017-01-18T08:00:00.000Z',
    '2017-01-03T08:00:00.000Z',
    '2017-01-10T08:00:00.000Z',
    '2017-01-24T08:00:00.000Z',
  ]);
});

it('should parse all recurring events without going on forever', function () {
  const events = new IcalExpander({ ics: recurIcs })
    .all();

  const outEvents = events.events.map(e => ({ startDate: e.startDate, summary: e.summary }));
  const outOccurrences = events.occurrences.map(o => ({ startDate: o.startDate, summary: o.item.summary }));
  const allEvents = [].concat(outEvents, outOccurrences);

  assert.equal(allEvents.length, 1001);
});

it('should correctly parse an ical file with invalid start/end dates', function () {
  const events = new IcalExpander({ ics: invalidDates, skipInvalidDates: true })
    .all();

  const outEvents = events.events.map(e => ({ startDate: e.startDate, summary: e.summary }));
  const outOccurrences = events.occurrences.map(o => ({ startDate: o.startDate, summary: o.item.summary }));
  const allEvents = [].concat(outEvents, outOccurrences);

  assert.equal(allEvents.length, 2);
});

it('should include events that are partially between two dates', function () {
  const eventIdsBetween = ['3', '4', '5', '6', '7'];
  const occurrenceIdsBetween = ['8'];

  const events = new IcalExpander({ ics: betweenTestCalendar })
    .between(new Date('2018-05-02T00:00:00.000Z'), new Date('2018-05-02T23:59:59.999Z'));
  assert.equal(events.events.length, 5);
  assert.equal(events.occurrences.length, 1);

  events.events.forEach((event) => {
    assert.ok(
      eventIdsBetween.findIndex(id => id === event.uid) >= 0,
      `${event.uid} is not a valid event between provided dates`);
  });

  events.occurrences.forEach((occurrence) => {
    assert.ok(
      occurrenceIdsBetween.findIndex(id => id === occurrence.item.uid) >= 0,
      `${occurrence.item.uid} is not a valid occurrence between provided dates`);
  });
});

it('should support open ended limits', function () {
  const events = new IcalExpander({ ics: allDayEventCalendar, maxIterations: 10 })
    .between(new Date('2018-05-19T23:59:00.000Z'));

  assert.equal(events.events.length, 1);
  assert(events.events[0].summary === 'Non-repeating all day event');
  assert.equal(events.occurrences.length, 10);
  assert(events.occurrences.every(o => o.item.summary === 'Repeating all day event'));

  // events.events.forEach(e => console.log(e.summary, e.uid));
  // events.occurrences.forEach(o => console.log(o.item.summary, o.item.uid));
});
<commit_msg>try to fix travis issue<commit_after>'use strict';

/* eslint-env mocha */
/* eslint-disable func-names, prefer-arrow-callback */

const fs = require('fs');
const IcalExpander = require('../');
const assert = require('assert');
const path = require('path');

// NOTE: Run with TZ=Etc/UTC mocha ical-parser.js
// https://github.com/mozilla-comm/ical.js/issues/257

const icaljsIssue257 = fs.readFileSync(path.join(__dirname, 'icaljs-issue-257.ics'), 'utf-8');
const icaljsIssue285 = fs.readFileSync(path.join(__dirname, 'icaljs-issue-285.ics'), 'utf-8');
const recurIcs = fs.readFileSync(path.join(__dirname, 'recur.ics'), 'utf-8');
const invalidDates = fs.readFileSync(path.join(__dirname, 'invalid_dates.ics'), 'utf-8');
const betweenTestCalendar = fs.readFileSync(path.join(__dirname, 'between_dates.ics'), 'utf-8');
const allDayEventCalendar = fs.readFileSync(path.join(__dirname, 'all-day.ics'), 'utf-8');

it('should show first date', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-07-24T00:00:00.000Z'), new Date('2016-07-26T00:00:00.000Z'));

  assert.equal(events.events[0].summary, 'Test-Event');
  assert.equal(events.occurrences.length, 0);
});

it('should show recurring modified date', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-07-31T00:00:00.000Z'), new Date('2016-08-02T00:00:00.000Z'));

  assert.equal(events.events[0].summary, 'Test-Event - Reccurence #2');
  assert.equal(events.occurrences.length, 0);
});

it('should show nothing at recurring exdate', function () {
  const events = new IcalExpander({ ics: icaljsIssue257 })
    .between(new Date('2016-08-07T00:00:00.000Z'), new Date('2016-08-10T00:00:00.000Z'));

  assert.equal(events.events.length, 0);
  assert.equal(events.occurrences.length, 0);
});

it('should parse issue 285 case correctly', function () {
  const events = new IcalExpander({ ics: icaljsIssue285 })
    .between(new Date('2017-01-03T00:00:00.000Z'), new Date('2017-01-25T00:00:00.000Z'));

  assert.deepEqual(events.events.map(e => e.startDate.toJSDate().toISOString()), ['2017-01-18T08:00:00.000Z']);
  assert.deepEqual(events.occurrences.map(e => e.startDate.toJSDate().toISOString()), [
    '2017-01-03T08:00:00.000Z',
    '2017-01-10T08:00:00.000Z',
    '2017-01-24T08:00:00.000Z',
  ]);
});

it('should parse all recurring events without going on forever', function () {
  const events = new IcalExpander({ ics: recurIcs })
    .all();

  const outEvents = events.events.map(e => ({ startDate: e.startDate, summary: e.summary }));
  const outOccurrences = events.occurrences.map(o => ({ startDate: o.startDate, summary: o.item.summary }));
  const allEvents = [].concat(outEvents, outOccurrences);

  assert.equal(allEvents.length, 1001);
});

it('should correctly parse an ical file with invalid start/end dates', function () {
  const events = new IcalExpander({ ics: invalidDates, skipInvalidDates: true })
    .all();

  const outEvents = events.events.map(e => ({ startDate: e.startDate, summary: e.summary }));
  const outOccurrences = events.occurrences.map(o => ({ startDate: o.startDate, summary: o.item.summary }));
  const allEvents = [].concat(outEvents, outOccurrences);

  assert.equal(allEvents.length, 2);
});

it('should include events that are partially between two dates', function () {
  const eventIdsBetween = ['3', '4', '5', '6', '7'];
  const occurrenceIdsBetween = ['8'];

  const events = new IcalExpander({ ics: betweenTestCalendar })
    .between(new Date('2018-05-02T00:00:00.000Z'), new Date('2018-05-02T23:59:59.999Z'));
  assert.equal(events.events.length, 5);
  assert.equal(events.occurrences.length, 1);

  events.events.forEach((event) => {
    assert.ok(
      eventIdsBetween.findIndex(id => id === event.uid) >= 0,
      `${event.uid} is not a valid event between provided dates`);
  });

  events.occurrences.forEach((occurrence) => {
    assert.ok(
      occurrenceIdsBetween.findIndex(id => id === occurrence.item.uid) >= 0,
      `${occurrence.item.uid} is not a valid occurrence between provided dates`);
  });
});

it('should support open ended limits', function () {
  const events = new IcalExpander({ ics: allDayEventCalendar, maxIterations: 10 })
    .between(new Date('2018-05-19T23:59:00.000Z'));

  assert.equal(events.events.length, 1);
  assert(events.events[0].summary === 'Non-repeating all day event');
  assert.equal(events.occurrences.length, 10);
  assert(events.occurrences.every(o => o.item.summary === 'Repeating all day event'));

  // events.events.forEach(e => console.log(e.summary, e.uid));
  // events.occurrences.forEach(o => console.log(o.item.summary, o.item.uid));
});
<|endoftext|>


<commit_before>'use strict';

var setupModuleLoader = require('../src/loader');
var createInjector = require('../src/injector');
var _ = require('lodash');

describe('injector', function () {
    beforeEach(function () {
        delete window.angular;
        setupModuleLoader(window);
    });

    it('can be created', function () {
        var injector = createInjector([]);
        expect(injector).toBeDefined();
    });

    it('has a constant that has been registered to a module', function () {
        var module = window.angular.module('myModule', []);
        module.constant('aConstant', 42);
        var injector = createInjector(['myModule']);
        expect(injector.has('aConstant')).toBe(true);
    });

    it('does not have a non-registered constant', function () {
        var module = window.angular.module('myModule', []);
        var injector = createInjector(['myModule']);
        expect(injector.has('aConstant')).toBe(false);
    });

    it('does not allow a constant called hasOwnProperty', function () {
        var module = window.angular.module('myModule', []);
        module.constant('hasOwnProperty', false);
        expect(function () {
            createInjector(['myModule']);
        }).toThrow();
    });

    it('can return a registered constant', function () {
        var module = window.angular.module('myModule', []);
        module.constant('aConstant', 42);
        var injector = createInjector(['myModule']);
        expect(injector.get('aConstant')).toBe(42);
    });

    it('loads multiple modules', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', []);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        var injector = createInjector(['myModule', 'myOtherModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
    });

    it('loads the required modules of a module', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', ['myModule']);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        var injector = createInjector(['myOtherModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
    });

    it('loads the transitively required modules of a module', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', ['myModule']);
        var module3 = window.angular.module('myThirdModule', ['myOtherModule']);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        module3.constant('aThirdConstant', 44);
        var injector = createInjector(['myThirdModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
        expect(injector.has('aThirdConstant')).toBe(true);
    });

    it('loads each module only once', function () {
        window.angular.module('myModule', ['myOtherModule']);
        window.angular.module('myOtherModule', ['myModule']);
        createInjector(['myModule']);
    });

    it('invokes an annotated function with dependency injection', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        module.constant('b', 2);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 'b'];

        expect(injector.invoke(fn)).toBe(3);
    });

    it('does not accept non-strings as injection tokens', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 2];

        expect(function () {
            injector.invoke(fn);
        }).toThrow();
    });

    it('invokes a function with the given this context', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        var injector = createInjector(['myModule']);

        var obj = {
            two: 2,
            fn: function (one) { return one + this.two; }
        };
        obj.fn.$inject = ['a'];

        expect(injector.invoke(obj.fn, obj)).toBe(3);
    });

    it('overrides dependencies with locals when invoking', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        module.constant('b', 2);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 'b'];

        expect(injector.invoke(fn, undefined, { b: 3 })).toBe(4);
    });

    describe('annotate', function () {
        it('returns the $inject annotation of a function when it has one', function () {
            var injector = createInjector([]);

            var fn = function () { };
            fn.$inject = ['a', 'b'];

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('returns the array-style annotations of a function', function () {
            var injector = createInjector([]);

            var fn = ['a', 'b', function () { }];

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('returns an empty array for a non-annotated 0-arg function', function () {
            var injector = createInjector([]);

            var fn = function () { };

            expect(injector.annotate(fn)).toEqual([]);
        });

        it('returns annotations parsed from function args when not annotated', function () {
            var injector = createInjector([]);

            var fn = function (a, b) { };

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('strips comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, /*b,*/ c) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips several comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, /*b,*/ c/*, d*/) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips // comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, //b,
                c) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips surrounding underscores from argument names when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, _b_, c_, _d, an_argument) { };

            expect(injector.annotate(fn)).toEqual(['a', 'b', 'c_', '_d', 'an_argument']);
        });

        it('throws when using a non-annotated fn in strict mode', function () {
            var injector = createInjector([], true);

            var fn = function (a, b, c) { };

            expect(function () {
                injector.annotate(fn);
            }).toThrow();
        });

        it('invokes an array-annotated function with dependency injection', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            var fn = ['a', 'b', function (one, two) { return one + two; }];

            expect(injector.invoke(fn)).toBe(3);
        });

        it('invokes a non-annotated function with dependency injection', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            var fn = function (a, b) { return a + b; };

            expect(injector.invoke(fn)).toBe(3);
        });

        it('instantiates an annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(one, two) {
                this.result = one + two;
            }
            Type.$inject = ['a', 'b'];

            var instance = injector.instantiate(Type);
            expect(instance.result).toBe(3);
        });

        it('instantiates an array-annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(one, two) {
                this.result = one + two;
            }

            var instance = injector.instantiate(['a', 'b', Type]);
            expect(instance.result).toBe(3);
        });

        it('instantiates a non-annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(a, b) {
                this.result = a + b;
            }

            var instance = injector.instantiate(Type);
            expect(instance.result).toBe(3);
        });

        it('uses the prototype of the constructor when instantiating', function () {
            function BaseType() { }
            BaseType.prototype.getValue = _.constant(42);

            function Type() { this.v = this.getValue(); }
            Type.prototype = BaseType.prototype;

            var module = window.angular.module('myModule', []);
            var injector = createInjector(['myModule']);

            var instance = injector.instantiate(Type);
            expect(instance.v).toBe(42);
        });

        it('supports locals when instantiating', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(a, b) {
                this.result = a + b;
            }

            var instance = injector.instantiate(Type, { b: 3 });
            expect(instance.result).toBe(4);
        });

        it('allows registering a provider and uses its $get', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', {
                $get: function () {
                    return 42;
                }
            });

            var injector = createInjector(['myModule']);

            expect(injector.has('a')).toBe(true);
            expect(injector.get('a')).toBe(42);
        });

        it('injects the $get method of a provider', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.provider('b', {
                $get: function (a) {
                    return a + 2;
                }
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('b')).toBe(3);
        });

        it('injects the $get method of a provider lazily', function () {
            var module = window.angular.module('myModule', []);
            module.provider('b', {
                $get: function (a) {
                    return a + 2;
                }
            });
            module.provider('a', { $get: _.constant(1) });

            var injector = createInjector(['myModule']);

            expect(injector.get('b')).toBe(3);
        });

        it('instantiates a dependency only once', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function () { return {}; } });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(injector.get('a'));
        });

        it('notifies the user about a circular dependency', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function (b) { } });
            module.provider('b', { $get: function (c) { } });
            module.provider('c', { $get: function (a) { } });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrowError(/Circular dependency found/);
        });

        it('cleans up the circular marker when instantiation fails', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', {
                $get: function () {
                    throw 'Failing instantiation!';
                }
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrow('Failing instantiation!');
            expect(function () {
                injector.get('a');
            }).toThrow('Failing instantiation!');
        });

        it('notifies the user about a circular dependency', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function (b) { } });
            module.provider('b', { $get: function (c) { } });
            module.provider('c', { $get: function (a) { } });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrowError('Circular dependency found: a <- c <- b <- a');
        });

        it('instantiates a provider if given as a constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 42; };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(42);
        });

        it('injects the given provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('b', 2);
            module.provider('a', function AProvider(b) {
                this.$get = function () { return 1 + b; };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(3);
        });

        it('injects another provider to a provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                var value = 1;
                this.setValue = function (v) { value = v; };
                this.$get = function () { return value; };
            });
            module.provider('b', function BProvider(aProvider) {
                aProvider.setValue(2);
                this.$get = function () { };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(2);
        });

        it('does not inject an instance to a provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });
            module.provider('b', function BProvider(a) {
                this.$get = function () { return a; };
            });

            expect(function () {
                createInjector(['myModule']);
            }).toThrow();
        });

        it('does not inject a provider to a $get function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });
            module.provider('b', function BProvider() {
                this.$get = function (aProvider) { return aProvider.$get(); };
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('b');
            }).toThrow();
        });

        it('does not inject a provider to invoke', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; }
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.invoke(function (aProvider) { });
            }).toThrow();
        });

        it('does not give access to providers through get', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('aProvider');
            }).toThrow();
        });

        it('registers constants first to make them available to providers', function () {
            var module = window.angular.module('myModule', []);

            module.provider('a', function AProvider(b) {
                this.$get = function () { return b; };
            });
            module.constant('b', 42);

            var injector = createInjector(['myModule']);
            expect(injector.get('a')).toBe(42);
        });
    });
});
<commit_msg>high level DI<commit_after>'use strict';

var setupModuleLoader = require('../src/loader');
var createInjector = require('../src/injector');
var _ = require('lodash');

describe('injector', function () {
    beforeEach(function () {
        delete window.angular;
        setupModuleLoader(window);
    });

    it('can be created', function () {
        var injector = createInjector([]);
        expect(injector).toBeDefined();
    });

    it('has a constant that has been registered to a module', function () {
        var module = window.angular.module('myModule', []);
        module.constant('aConstant', 42);
        var injector = createInjector(['myModule']);
        expect(injector.has('aConstant')).toBe(true);
    });

    it('does not have a non-registered constant', function () {
        var module = window.angular.module('myModule', []);
        var injector = createInjector(['myModule']);
        expect(injector.has('aConstant')).toBe(false);
    });

    it('does not allow a constant called hasOwnProperty', function () {
        var module = window.angular.module('myModule', []);
        module.constant('hasOwnProperty', false);
        expect(function () {
            createInjector(['myModule']);
        }).toThrow();
    });

    it('can return a registered constant', function () {
        var module = window.angular.module('myModule', []);
        module.constant('aConstant', 42);
        var injector = createInjector(['myModule']);
        expect(injector.get('aConstant')).toBe(42);
    });

    it('loads multiple modules', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', []);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        var injector = createInjector(['myModule', 'myOtherModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
    });

    it('loads the required modules of a module', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', ['myModule']);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        var injector = createInjector(['myOtherModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
    });

    it('loads the transitively required modules of a module', function () {
        var module1 = window.angular.module('myModule', []);
        var module2 = window.angular.module('myOtherModule', ['myModule']);
        var module3 = window.angular.module('myThirdModule', ['myOtherModule']);
        module1.constant('aConstant', 42);
        module2.constant('anotherConstant', 43);
        module3.constant('aThirdConstant', 44);
        var injector = createInjector(['myThirdModule']);

        expect(injector.has('aConstant')).toBe(true);
        expect(injector.has('anotherConstant')).toBe(true);
        expect(injector.has('aThirdConstant')).toBe(true);
    });

    it('loads each module only once', function () {
        window.angular.module('myModule', ['myOtherModule']);
        window.angular.module('myOtherModule', ['myModule']);
        createInjector(['myModule']);
    });

    it('invokes an annotated function with dependency injection', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        module.constant('b', 2);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 'b'];

        expect(injector.invoke(fn)).toBe(3);
    });

    it('does not accept non-strings as injection tokens', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 2];

        expect(function () {
            injector.invoke(fn);
        }).toThrow();
    });

    it('invokes a function with the given this context', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        var injector = createInjector(['myModule']);

        var obj = {
            two: 2,
            fn: function (one) { return one + this.two; }
        };
        obj.fn.$inject = ['a'];

        expect(injector.invoke(obj.fn, obj)).toBe(3);
    });

    it('overrides dependencies with locals when invoking', function () {
        var module = window.angular.module('myModule', []);
        module.constant('a', 1);
        module.constant('b', 2);
        var injector = createInjector(['myModule']);

        var fn = function (one, two) { return one + two; };
        fn.$inject = ['a', 'b'];

        expect(injector.invoke(fn, undefined, { b: 3 })).toBe(4);
    });

    describe('annotate', function () {
        it('returns the $inject annotation of a function when it has one', function () {
            var injector = createInjector([]);

            var fn = function () { };
            fn.$inject = ['a', 'b'];

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('returns the array-style annotations of a function', function () {
            var injector = createInjector([]);

            var fn = ['a', 'b', function () { }];

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('returns an empty array for a non-annotated 0-arg function', function () {
            var injector = createInjector([]);

            var fn = function () { };

            expect(injector.annotate(fn)).toEqual([]);
        });

        it('returns annotations parsed from function args when not annotated', function () {
            var injector = createInjector([]);

            var fn = function (a, b) { };

            expect(injector.annotate(fn)).toEqual(['a', 'b']);
        });

        it('strips comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, /*b,*/ c) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips several comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, /*b,*/ c/*, d*/) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips // comments from argument lists when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, //b,
                c) { };

            expect(injector.annotate(fn)).toEqual(['a', 'c']);
        });

        it('strips surrounding underscores from argument names when parsing', function () {
            var injector = createInjector([]);

            var fn = function (a, _b_, c_, _d, an_argument) { };

            expect(injector.annotate(fn)).toEqual(['a', 'b', 'c_', '_d', 'an_argument']);
        });

        it('throws when using a non-annotated fn in strict mode', function () {
            var injector = createInjector([], true);

            var fn = function (a, b, c) { };

            expect(function () {
                injector.annotate(fn);
            }).toThrow();
        });

        it('invokes an array-annotated function with dependency injection', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            var fn = ['a', 'b', function (one, two) { return one + two; }];

            expect(injector.invoke(fn)).toBe(3);
        });

        it('invokes a non-annotated function with dependency injection', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            var fn = function (a, b) { return a + b; };

            expect(injector.invoke(fn)).toBe(3);
        });

        it('instantiates an annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(one, two) {
                this.result = one + two;
            }
            Type.$inject = ['a', 'b'];

            var instance = injector.instantiate(Type);
            expect(instance.result).toBe(3);
        });

        it('instantiates an array-annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(one, two) {
                this.result = one + two;
            }

            var instance = injector.instantiate(['a', 'b', Type]);
            expect(instance.result).toBe(3);
        });

        it('instantiates a non-annotated constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(a, b) {
                this.result = a + b;
            }

            var instance = injector.instantiate(Type);
            expect(instance.result).toBe(3);
        });

        it('uses the prototype of the constructor when instantiating', function () {
            function BaseType() { }
            BaseType.prototype.getValue = _.constant(42);

            function Type() { this.v = this.getValue(); }
            Type.prototype = BaseType.prototype;

            var module = window.angular.module('myModule', []);
            var injector = createInjector(['myModule']);

            var instance = injector.instantiate(Type);
            expect(instance.v).toBe(42);
        });

        it('supports locals when instantiating', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.constant('b', 2);
            var injector = createInjector(['myModule']);

            function Type(a, b) {
                this.result = a + b;
            }

            var instance = injector.instantiate(Type, { b: 3 });
            expect(instance.result).toBe(4);
        });

        it('allows registering a provider and uses its $get', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', {
                $get: function () {
                    return 42;
                }
            });

            var injector = createInjector(['myModule']);

            expect(injector.has('a')).toBe(true);
            expect(injector.get('a')).toBe(42);
        });

        it('injects the $get method of a provider', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 1);
            module.provider('b', {
                $get: function (a) {
                    return a + 2;
                }
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('b')).toBe(3);
        });

        it('injects the $get method of a provider lazily', function () {
            var module = window.angular.module('myModule', []);
            module.provider('b', {
                $get: function (a) {
                    return a + 2;
                }
            });
            module.provider('a', { $get: _.constant(1) });

            var injector = createInjector(['myModule']);

            expect(injector.get('b')).toBe(3);
        });

        it('instantiates a dependency only once', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function () { return {}; } });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(injector.get('a'));
        });

        it('notifies the user about a circular dependency', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function (b) { } });
            module.provider('b', { $get: function (c) { } });
            module.provider('c', { $get: function (a) { } });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrowError(/Circular dependency found/);
        });

        it('cleans up the circular marker when instantiation fails', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', {
                $get: function () {
                    throw 'Failing instantiation!';
                }
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrow('Failing instantiation!');
            expect(function () {
                injector.get('a');
            }).toThrow('Failing instantiation!');
        });

        it('notifies the user about a circular dependency', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', { $get: function (b) { } });
            module.provider('b', { $get: function (c) { } });
            module.provider('c', { $get: function (a) { } });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('a');
            }).toThrowError('Circular dependency found: a <- c <- b <- a');
        });

        it('instantiates a provider if given as a constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 42; };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(42);
        });

        it('injects the given provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.constant('b', 2);
            module.provider('a', function AProvider(b) {
                this.$get = function () { return 1 + b; };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(3);
        });

        it('injects another provider to a provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                var value = 1;
                this.setValue = function (v) { value = v; };
                this.$get = function () { return value; };
            });
            module.provider('b', function BProvider(aProvider) {
                aProvider.setValue(2);
                this.$get = function () { };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('a')).toBe(2);
        });

        it('does not inject an instance to a provider constructor function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });
            module.provider('b', function BProvider(a) {
                this.$get = function () { return a; };
            });

            expect(function () {
                createInjector(['myModule']);
            }).toThrow();
        });

        it('does not inject a provider to a $get function', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });
            module.provider('b', function BProvider() {
                this.$get = function (aProvider) { return aProvider.$get(); };
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('b');
            }).toThrow();
        });

        it('does not inject a provider to invoke', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; }
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.invoke(function (aProvider) { });
            }).toThrow();
        });

        it('does not give access to providers through get', function () {
            var module = window.angular.module('myModule', []);
            module.provider('a', function AProvider() {
                this.$get = function () { return 1; };
            });

            var injector = createInjector(['myModule']);

            expect(function () {
                injector.get('aProvider');
            }).toThrow();
        });

        it('registers constants first to make them available to providers', function () {
            var module = window.angular.module('myModule', []);

            module.provider('a', function AProvider(b) {
                this.$get = function () { return b; };
            });
            module.constant('b', 42);

            var injector = createInjector(['myModule']);
            expect(injector.get('a')).toBe(42);
        });

        it('allows injecting the instance injector to $get', function () {
            var module = window.angular.module('myModule', []);
            module.constant('a', 42);
            module.provider('b', function BProvider() {
                this.$get = function ($injector) {
                    return $injector.get('a');
                };
            });

            var injector = createInjector(['myModule']);

            expect(injector.get('b')).toBe(42);
        });
    });
});
<|endoftext|>


<commit_before>if (typeof(require) !== 'undefined') { var tree = require('less/tree') }

tree.Comment = function Comment(value) {
    this.value = value;
};
tree.Comment.prototype = {
    toCSS: function () {
        return this.value;
    },
};
<commit_msg>removed trailing comma, which breaks minification<commit_after>if (typeof(require) !== 'undefined') { var tree = require('less/tree') }

tree.Comment = function Comment(value) {
    this.value = value;
};
tree.Comment.prototype = {
    toCSS: function () {
        return this.value;
    }
};
<|endoftext|>


<commit_before>(function (tree) {

tree.Ruleset = function (selectors, rules) {
    this.selectors = selectors;
    this.rules = rules;
    this._lookups = {};
};
tree.Ruleset.prototype = {
    eval: function () { return this },
    evalRules: function (context) {
        var rules = [];

        this.rules.forEach(function (rule) {
            if (rule.evalRules) {
                rules.push(rule.evalRules(context));
            } else if (rule instanceof tree.mixin.Call) {
                Array.prototype.push.apply(rules, rule.eval(context));
            } else if (! (rule instanceof tree.mixin.Definition)) {
                rules.push(rule.eval ? rule.eval(context) : '');
            }
        });
        this.rules = rules;
        return this;
    },
    match: function (args) {
        return !args || args.length === 0;
    },
    variable: function (name) {
        if (this._variables) { return this._variables[name] }
        else {
            return (this._variables = this.rules.reduce(function (hash, r) {
                if (r instanceof tree.Rule && r.variable === true) {
                    hash[r.name] = r;
                }
                return hash;
            }, {}))[name];
        }
    },
    rulesets: function () {
        if (this._rulesets) { return this._rulesets }
        else {
            return this._rulesets = this.rules.filter(function (r) {
                if (r instanceof tree.Ruleset || r instanceof tree.mixin.Definition) { return r }
            });
        }
    },
    find: function (selector, self) {
        self = self || this;
        var rules = [], rule, match,
            key = selector.toCSS();

        if (key in this._lookups) { return this._lookups[key] }

        this.rulesets().forEach(function (rule) {
            if (rule !== self) {
                for (var j = 0; j < rule.selectors.length; j++) {
                    if (match = selector.match(rule.selectors[j])) {
                        if (selector.elements.length > 1) {
                            Array.prototype.push.apply(rules, rule.find(
                                new(tree.Selector)(selector.elements.slice(1)), self));
                        } else {
                            rules.push(rule);
                        }
                        break;
                    }
                }
            }
        });
        return this._lookups[key] = rules;
    },
    //
    // Entry point for code generation
    //
    //     `context` holds an array of arrays.
    //
    toCSS: function (context, env) {
        var css = [],      // The CSS output
            rules = [],    // node.Rule instances
            rulesets = [], // node.Ruleset instances
            paths = [],    // Current selectors
            selector,      // The fully rendered selector
            rule;

        if (! this.root) {
            if (context.length === 0) {
                paths = this.selectors.map(function (s) { return [s] });
            } else {
                for (var s = 0; s < this.selectors.length; s++) {
                    for (var c = 0; c < context.length; c++) {
                        paths.push(context[c].concat([this.selectors[s]]));
                    }
                }
            }
        } else {
            for (var i = 0; i < this.rules.length; i++) {
                if (this.rules[i] instanceof tree.Import) {
                    Array.prototype.splice
                         .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
                }
            }
        }

        // push the current ruleset to the frames stack
        env.frames.unshift(this);

        // Evaluate mixin calls and store the frames around mixin definitions,
        // so they can be evaluated like closures when the time comes.
        for (var i = 0; i < this.rules.length; i++) {
            if (this.rules[i] instanceof tree.mixin.Call) {
                Array.prototype.splice
                     .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
            } else if (this.rules[i] instanceof tree.mixin.Definition) {
                this.rules[i].frames = env.frames.slice(0);
            }
        }

        // Evaluate rules and rulesets
        for (var i = 0; i < this.rules.length; i++) {
            rule = this.rules[i];

            if (rule instanceof tree.Directive) {
                rulesets.push(rule.eval(env).toCSS(paths, env));
            } else if (rule.rules) {
                rulesets.push(rule.toCSS(paths, env));
            } else if (rule instanceof tree.Comment) {
                if (!rule.silent) {
                    if (this.root) {
                        rulesets.push(rule.toCSS(env));
                    } else {
                        rules.push(rule.toCSS(env));
                    }
                }
            } else {
                if (rule.toCSS && !rule.variable) {
                    rules.push(rule.eval(env).toCSS(env));
                } else if (rule.value && !rule.variable) {
                    rules.push(rule.value.toString());
                }
            }
        }

        rulesets = rulesets.join('');

        // If this is the root node, we don't render
        // a selector, or {}.
        // Otherwise, only output if this ruleset has rules.
        if (this.root) {
            css.push(rules.join(env.compress ? '' : '\n'));
        } else {
            if (rules.length > 0) {
                selector = paths.map(function (p) {
                    return p.map(function (s) {
                        return s.toCSS(env);
                    }).join('').trim();
                }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
                css.push(selector,
                        (env.compress ? '{' : ' {\n  ') +
                        rules.join(env.compress ? '' : '\n  ') +
                        (env.compress ? '}' : '\n}\n'));
            }
        }
        css.push(rulesets);

        // Pop the stack
        env.frames.shift();

        return css.join('') + (env.compress ? '\n' : '');
    }
};
})(require('less/tree'));
<commit_msg>(minor) refactoring<commit_after>(function (tree) {

tree.Ruleset = function (selectors, rules) {
    this.selectors = selectors;
    this.rules = rules;
    this._lookups = {};
};
tree.Ruleset.prototype = {
    eval: function () { return this },
    evalRules: function (context) {
        var rules = [];

        this.rules.forEach(function (rule) {
            if (rule.evalRules) {
                rules.push(rule.evalRules(context));
            } else if (rule instanceof tree.mixin.Call) {
                Array.prototype.push.apply(rules, rule.eval(context));
            } else if (! (rule instanceof tree.mixin.Definition)) {
                rules.push(rule.eval ? rule.eval(context) : '');
            }
        });
        this.rules = rules;
        return this;
    },
    match: function (args) {
        return !args || args.length === 0;
    },
    variable: function (name) {
        if (this._variables) { return this._variables[name] }
        else {
            return (this._variables = this.rules.reduce(function (hash, r) {
                if (r instanceof tree.Rule && r.variable === true) {
                    hash[r.name] = r;
                }
                return hash;
            }, {}))[name];
        }
    },
    rulesets: function () {
        if (this._rulesets) { return this._rulesets }
        else {
            return this._rulesets = this.rules.filter(function (r) {
                return (r instanceof tree.Ruleset) || (r instanceof tree.mixin.Definition);
            });
        }
    },
    find: function (selector, self) {
        self = self || this;
        var rules = [], rule, match,
            key = selector.toCSS();

        if (key in this._lookups) { return this._lookups[key] }

        this.rulesets().forEach(function (rule) {
            if (rule !== self) {
                for (var j = 0; j < rule.selectors.length; j++) {
                    if (match = selector.match(rule.selectors[j])) {
                        if (selector.elements.length > 1) {
                            Array.prototype.push.apply(rules, rule.find(
                                new(tree.Selector)(selector.elements.slice(1)), self));
                        } else {
                            rules.push(rule);
                        }
                        break;
                    }
                }
            }
        });
        return this._lookups[key] = rules;
    },
    //
    // Entry point for code generation
    //
    //     `context` holds an array of arrays.
    //
    toCSS: function (context, env) {
        var css = [],      // The CSS output
            rules = [],    // node.Rule instances
            rulesets = [], // node.Ruleset instances
            paths = [],    // Current selectors
            selector,      // The fully rendered selector
            rule;

        if (! this.root) {
            if (context.length === 0) {
                paths = this.selectors.map(function (s) { return [s] });
            } else {
                for (var s = 0; s < this.selectors.length; s++) {
                    for (var c = 0; c < context.length; c++) {
                        paths.push(context[c].concat([this.selectors[s]]));
                    }
                }
            }
        } else {
            for (var i = 0; i < this.rules.length; i++) {
                if (this.rules[i] instanceof tree.Import) {
                    Array.prototype.splice
                         .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
                }
            }
        }

        // push the current ruleset to the frames stack
        env.frames.unshift(this);

        // Evaluate mixin calls and store the frames around mixin definitions,
        // so they can be evaluated like closures when the time comes.
        for (var i = 0; i < this.rules.length; i++) {
            if (this.rules[i] instanceof tree.mixin.Call) {
                Array.prototype.splice
                     .apply(this.rules, [i, 1].concat(this.rules[i].eval(env)));
            } else if (this.rules[i] instanceof tree.mixin.Definition) {
                this.rules[i].frames = env.frames.slice(0);
            }
        }

        // Evaluate rules and rulesets
        for (var i = 0; i < this.rules.length; i++) {
            rule = this.rules[i];

            if (rule instanceof tree.Directive) {
                rulesets.push(rule.eval(env).toCSS(paths, env));
            } else if (rule.rules) {
                rulesets.push(rule.toCSS(paths, env));
            } else if (rule instanceof tree.Comment) {
                if (!rule.silent) {
                    if (this.root) {
                        rulesets.push(rule.toCSS(env));
                    } else {
                        rules.push(rule.toCSS(env));
                    }
                }
            } else {
                if (rule.toCSS && !rule.variable) {
                    rules.push(rule.eval(env).toCSS(env));
                } else if (rule.value && !rule.variable) {
                    rules.push(rule.value.toString());
                }
            }
        }

        rulesets = rulesets.join('');

        // If this is the root node, we don't render
        // a selector, or {}.
        // Otherwise, only output if this ruleset has rules.
        if (this.root) {
            css.push(rules.join(env.compress ? '' : '\n'));
        } else {
            if (rules.length > 0) {
                selector = paths.map(function (p) {
                    return p.map(function (s) {
                        return s.toCSS(env);
                    }).join('').trim();
                }).join(env.compress ? ',' : (paths.length > 3 ? ',\n' : ', '));
                css.push(selector,
                        (env.compress ? '{' : ' {\n  ') +
                        rules.join(env.compress ? '' : '\n  ') +
                        (env.compress ? '}' : '\n}\n'));
            }
        }
        css.push(rulesets);

        // Pop the stack
        env.frames.shift();

        return css.join('') + (env.compress ? '\n' : '');
    }
};
})(require('less/tree'));
<|endoftext|>


<commit_before>/**
 * Copyright 2017 Google Inc. All rights reserved.
 * Modifications copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const path = require('path');
const fs = require('fs');
const utils = require('./utils');
const { makeUserDataDir, removeUserDataDir } = utils;
const {FFOX, CHROMIUM, WEBKIT, WIN} = utils.testOptions(browserType);

describe('Playwright', function() {
  describe('browserType.launch', function() {
    it('should reject all promises when browser is closed', async({browserType, defaultBrowserOptions}) => {
      const browser = await browserType.launch(defaultBrowserOptions);
      const page = await (await browser.newContext()).newPage();
      let error = null;
      const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
      await browser.close();
      await neverResolves;
      expect(error.message).toContain('Protocol error');
    });
    it('should throw if userDataDir option is passed', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, {userDataDir: 'random-path'});
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('launchPersistentContext');
    });
    it('should throw if page argument is passed', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] });
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('can not specify page');
    });
    it('should reject if executable path is invalid', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, {executablePath: 'random-invalid-path'});
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('Failed to launch');
    });
  });

  describe('browserType.launchPersistentContext', function() {
    it('should have default URL when launching browser', async ({browserType, defaultBrowserOptions}) => {
      const userDataDir = await makeUserDataDir();
      const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
      const urls = browserContext.pages().map(page => page.url());
      expect(urls).toEqual(['about:blank']);
      await browserContext.close();
      await removeUserDataDir(userDataDir);
    });
    it('should have custom URL when launching browser', async ({browserType, defaultBrowserOptions, server}) => {
      const userDataDir = await makeUserDataDir();
      const options = Object.assign({}, defaultBrowserOptions);
      options.args = [server.EMPTY_PAGE].concat(options.args || []);
      const browserContext = await browserType.launchPersistentContext(userDataDir, options);
      const pages = browserContext.pages();
      expect(pages.length).toBe(1);
      const page = pages[0];
      if (page.url() !== server.EMPTY_PAGE) {
        await page.waitForNavigation();
      }
      expect(page.url()).toBe(server.EMPTY_PAGE);
      await browserContext.close();
      await removeUserDataDir(userDataDir);
    });
  });

  describe('browserType.launchServer', function() {
    it('should return child_process instance', async ({browserType, defaultBrowserOptions}) => {
      const browserServer = await browserType.launchServer(defaultBrowserOptions);
      expect(browserServer.process().pid).toBeGreaterThan(0);
      await browserServer.close();
    });
    it('should fire close event', async ({browserType, defaultBrowserOptions}) => {
      const browserServer = await browserType.launchServer(defaultBrowserOptions);
      await Promise.all([
        new Promise(f => browserServer.on('close', f)),
        browserServer.close(),
      ]);
    });
  });

  describe('browserType.executablePath', function() {
    it('should work', async({browserType}) => {
      const executablePath = browserType.executablePath();
      expect(fs.existsSync(executablePath)).toBe(true);
      expect(fs.realpathSync(executablePath)).toBe(executablePath);
    });
  });

  describe('browserType.name', function() {
    it('should work', async({browserType}) => {
      if (WEBKIT)
        expect(browserType.name()).toBe('webkit');
      else if (FFOX)
        expect(browserType.name()).toBe('firefox');
      else if (CHROMIUM)
        expect(browserType.name()).toBe('chromium');
      else
        throw new Error('Unknown browser');
    });
  });
});

describe('Top-level requires', function() {
  it('should require top-level Errors', async() => {
    const Errors = require(path.join(utils.projectRoot(), '/lib/errors.js'));
    expect(Errors.TimeoutError).toBe(playwright.errors.TimeoutError);
  });
  it('should require top-level DeviceDescriptors', async() => {
    const Devices = require(path.join(utils.projectRoot(), '/lib/deviceDescriptors.js')).DeviceDescriptors;
    expect(Devices['iPhone 6']).toBeTruthy();
    expect(Devices['iPhone 6']).toBe(playwright.devices['iPhone 6']);
  });
});

describe('Browser.isConnected', () => {
  it('should set the browser connected state', async ({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    expect(remote.isConnected()).toBe(true);
    await remote.close();
    expect(remote.isConnected()).toBe(false);
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should throw when used after isConnected returns false', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    await Promise.all([
      browserServer.close(),
      new Promise(f => remote.once('disconnected', f)),
    ]);
    expect(remote.isConnected()).toBe(false);
    const error = await page.evaluate('1 + 1').catch(e => e);
    expect(error.message).toContain('has been closed');
  });
});

describe('Browser.disconnect', function() {
  it('should reject navigation when browser closes', async({browserType, defaultBrowserOptions, server}) => {
    server.setRoute('/one-style.css', () => {});
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
    await server.waitForRequest('/one-style.css');
    await remote.close();
    const error = await navigationPromise;
    expect(error.message).toContain('Navigation failed because browser has disconnected!');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should reject waitForSelector when browser closes', async({browserType, defaultBrowserOptions, server}) => {
    server.setRoute('/empty.html', () => {});
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    const watchdog = page.waitForSelector('div', { timeout: 60000 }).catch(e => e);

    // Make sure the previous waitForSelector has time to make it to the browser before we disconnect.
    await page.waitForSelector('body');

    await remote.close();
    const error = await watchdog;
    expect(error.message).toContain('Protocol error');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should throw if used after disconnect', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    await remote.close();
    const error = await page.evaluate('1 + 1').catch(e => e);
    expect(error.message).toContain('has been closed');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should emit close events on pages and contexts', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const context = await remote.newContext();
    const page = await context.newPage();
    let pageClosed = false;
    page.on('close', e => pageClosed = true);
    await Promise.all([
      new Promise(f => context.on('close', f)),
      browserServer.close()
    ]);
    expect(pageClosed).toBeTruthy();
  });
});

describe('Browser.close', function() {
  it('should terminate network waiters', async({browserType, defaultBrowserOptions, server}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const newPage = await remote.newPage();
    const results = await Promise.all([
      newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
      newPage.waitForResponse(server.EMPTY_PAGE).catch(e => e),
      browserServer.close()
    ]);
    for (let i = 0; i < 2; i++) {
      const message = results[i].message;
      expect(message).toContain('Target closed');
      expect(message).not.toContain('Timeout');
    }
  });
  it('should fire close event for all contexts', async({browserType, defaultBrowserOptions}) => {
    const browser = await browserType.launch(defaultBrowserOptions);
    const context = await browser.newContext();
    let closed = false;
    context.on('close', () => closed = true);
    await browser.close();
    expect(closed).toBe(true);
  });
});

describe('browserType.launch |webSocket| option', function() {
  it('should support the webSocket option', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const browserContext = await browser.newContext();
    expect(browserContext.pages().length).toBe(0);
    expect(browserServer.wsEndpoint()).not.toBe(null);
    const page = await browserContext.newPage();
    expect(await page.evaluate('11 * 11')).toBe(121);
    await page.close();
    await browser.close();
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should fire "disconnected" when closing with webSocket', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
    const closedPromise = new Promise(f => browserServer.on('close', f));
    browserServer.kill();
    await Promise.all([
      disconnectedEventPromise,
      closedPromise,
    ]);
  });
});

describe('browserType.connect', function() {
  it.slow()('should be able to reconnect to a browser', async({browserType, defaultBrowserOptions, server}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    {
      const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
      const browserContext = await browser.newContext();
      const page = await browserContext.newPage();
      await page.goto(server.EMPTY_PAGE);
      await browser.close();
    }
    {
      const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
      const browserContext = await browser.newContext();
      const page = await browserContext.newPage();
      await page.goto(server.EMPTY_PAGE);
      await browser.close();
    }
    await browserServer._checkLeaks();
    await browserServer.close();
  });
});

describe('browserType.launchPersistentContext', function() {
  it('userDataDir option', async({browserType, defaultBrowserOptions}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    // Open a page to make sure its functional.
    await browserContext.newPage();
    expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
    await browserContext.close();
    expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
  });
  it.slow()('userDataDir option should restore state', async({browserType, defaultBrowserOptions, server}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page = await browserContext.newPage();
    await page.goto(server.EMPTY_PAGE);
    await page.evaluate(() => localStorage.hey = 'hello');
    await browserContext.close();

    const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page2 = await browserContext2.newPage();
    await page2.goto(server.EMPTY_PAGE);
    expect(await page2.evaluate(() => localStorage.hey)).toBe('hello');
    await browserContext2.close();

    const userDataDir2 = await makeUserDataDir();
    const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions);
    const page3 = await browserContext3.newPage();
    await page3.goto(server.EMPTY_PAGE);
    expect(await page3.evaluate(() => localStorage.hey)).not.toBe('hello');
    await browserContext3.close();

    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
    await removeUserDataDir(userDataDir2);
  });
  // TODO: Flaky! See https://github.com/microsoft/playwright/pull/1795/checks?check_run_id=587685496
  it.slow().fail(WIN && CHROMIUM)('userDataDir option should restore cookies', async({browserType, defaultBrowserOptions,  server}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page = await browserContext.newPage();
    await page.goto(server.EMPTY_PAGE);
    await page.evaluate(() => document.cookie = 'doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT');
    await browserContext.close();

    const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page2 = await browserContext2.newPage();
    await page2.goto(server.EMPTY_PAGE);
    expect(await page2.evaluate(() => document.cookie)).toBe('doSomethingOnlyOnce=true');
    await browserContext2.close();

    const userDataDir2 = await makeUserDataDir();
    const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions);
    const page3 = await browserContext3.newPage();
    await page3.goto(server.EMPTY_PAGE);
    expect(await page3.evaluate(() => localStorage.hey)).not.toBe('doSomethingOnlyOnce=true');
    await browserContext3.close();

    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
    await removeUserDataDir(userDataDir2);
  });
});
<commit_msg>test: unflake launcher test (#2049)<commit_after>/**
 * Copyright 2017 Google Inc. All rights reserved.
 * Modifications copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const path = require('path');
const fs = require('fs');
const utils = require('./utils');
const { makeUserDataDir, removeUserDataDir } = utils;
const {FFOX, CHROMIUM, WEBKIT, WIN} = utils.testOptions(browserType);

describe('Playwright', function() {
  describe('browserType.launch', function() {
    it('should reject all promises when browser is closed', async({browserType, defaultBrowserOptions}) => {
      const browser = await browserType.launch(defaultBrowserOptions);
      const page = await (await browser.newContext()).newPage();
      let error = null;
      const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
      await page.evaluate(() => new Promise(f => setTimeout(f, 0)));
      await browser.close();
      await neverResolves;
      expect(error.message).toContain('Protocol error');
    });
    it('should throw if userDataDir option is passed', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, {userDataDir: 'random-path'});
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('launchPersistentContext');
    });
    it('should throw if page argument is passed', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] });
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('can not specify page');
    });
    it('should reject if executable path is invalid', async({browserType, defaultBrowserOptions}) => {
      let waitError = null;
      const options = Object.assign({}, defaultBrowserOptions, {executablePath: 'random-invalid-path'});
      await browserType.launch(options).catch(e => waitError = e);
      expect(waitError.message).toContain('Failed to launch');
    });
  });

  describe('browserType.launchPersistentContext', function() {
    it('should have default URL when launching browser', async ({browserType, defaultBrowserOptions}) => {
      const userDataDir = await makeUserDataDir();
      const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
      const urls = browserContext.pages().map(page => page.url());
      expect(urls).toEqual(['about:blank']);
      await browserContext.close();
      await removeUserDataDir(userDataDir);
    });
    it('should have custom URL when launching browser', async ({browserType, defaultBrowserOptions, server}) => {
      const userDataDir = await makeUserDataDir();
      const options = Object.assign({}, defaultBrowserOptions);
      options.args = [server.EMPTY_PAGE].concat(options.args || []);
      const browserContext = await browserType.launchPersistentContext(userDataDir, options);
      const pages = browserContext.pages();
      expect(pages.length).toBe(1);
      const page = pages[0];
      if (page.url() !== server.EMPTY_PAGE) {
        await page.waitForNavigation();
      }
      expect(page.url()).toBe(server.EMPTY_PAGE);
      await browserContext.close();
      await removeUserDataDir(userDataDir);
    });
  });

  describe('browserType.launchServer', function() {
    it('should return child_process instance', async ({browserType, defaultBrowserOptions}) => {
      const browserServer = await browserType.launchServer(defaultBrowserOptions);
      expect(browserServer.process().pid).toBeGreaterThan(0);
      await browserServer.close();
    });
    it('should fire close event', async ({browserType, defaultBrowserOptions}) => {
      const browserServer = await browserType.launchServer(defaultBrowserOptions);
      await Promise.all([
        new Promise(f => browserServer.on('close', f)),
        browserServer.close(),
      ]);
    });
  });

  describe('browserType.executablePath', function() {
    it('should work', async({browserType}) => {
      const executablePath = browserType.executablePath();
      expect(fs.existsSync(executablePath)).toBe(true);
      expect(fs.realpathSync(executablePath)).toBe(executablePath);
    });
  });

  describe('browserType.name', function() {
    it('should work', async({browserType}) => {
      if (WEBKIT)
        expect(browserType.name()).toBe('webkit');
      else if (FFOX)
        expect(browserType.name()).toBe('firefox');
      else if (CHROMIUM)
        expect(browserType.name()).toBe('chromium');
      else
        throw new Error('Unknown browser');
    });
  });
});

describe('Top-level requires', function() {
  it('should require top-level Errors', async() => {
    const Errors = require(path.join(utils.projectRoot(), '/lib/errors.js'));
    expect(Errors.TimeoutError).toBe(playwright.errors.TimeoutError);
  });
  it('should require top-level DeviceDescriptors', async() => {
    const Devices = require(path.join(utils.projectRoot(), '/lib/deviceDescriptors.js')).DeviceDescriptors;
    expect(Devices['iPhone 6']).toBeTruthy();
    expect(Devices['iPhone 6']).toBe(playwright.devices['iPhone 6']);
  });
});

describe('Browser.isConnected', () => {
  it('should set the browser connected state', async ({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    expect(remote.isConnected()).toBe(true);
    await remote.close();
    expect(remote.isConnected()).toBe(false);
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should throw when used after isConnected returns false', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    await Promise.all([
      browserServer.close(),
      new Promise(f => remote.once('disconnected', f)),
    ]);
    expect(remote.isConnected()).toBe(false);
    const error = await page.evaluate('1 + 1').catch(e => e);
    expect(error.message).toContain('has been closed');
  });
});

describe('Browser.disconnect', function() {
  it('should reject navigation when browser closes', async({browserType, defaultBrowserOptions, server}) => {
    server.setRoute('/one-style.css', () => {});
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
    await server.waitForRequest('/one-style.css');
    await remote.close();
    const error = await navigationPromise;
    expect(error.message).toContain('Navigation failed because browser has disconnected!');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should reject waitForSelector when browser closes', async({browserType, defaultBrowserOptions, server}) => {
    server.setRoute('/empty.html', () => {});
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    const watchdog = page.waitForSelector('div', { timeout: 60000 }).catch(e => e);

    // Make sure the previous waitForSelector has time to make it to the browser before we disconnect.
    await page.waitForSelector('body');

    await remote.close();
    const error = await watchdog;
    expect(error.message).toContain('Protocol error');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should throw if used after disconnect', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const page = await remote.newPage();
    await remote.close();
    const error = await page.evaluate('1 + 1').catch(e => e);
    expect(error.message).toContain('has been closed');
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should emit close events on pages and contexts', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const context = await remote.newContext();
    const page = await context.newPage();
    let pageClosed = false;
    page.on('close', e => pageClosed = true);
    await Promise.all([
      new Promise(f => context.on('close', f)),
      browserServer.close()
    ]);
    expect(pageClosed).toBeTruthy();
  });
});

describe('Browser.close', function() {
  it('should terminate network waiters', async({browserType, defaultBrowserOptions, server}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const newPage = await remote.newPage();
    const results = await Promise.all([
      newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
      newPage.waitForResponse(server.EMPTY_PAGE).catch(e => e),
      browserServer.close()
    ]);
    for (let i = 0; i < 2; i++) {
      const message = results[i].message;
      expect(message).toContain('Target closed');
      expect(message).not.toContain('Timeout');
    }
  });
  it('should fire close event for all contexts', async({browserType, defaultBrowserOptions}) => {
    const browser = await browserType.launch(defaultBrowserOptions);
    const context = await browser.newContext();
    let closed = false;
    context.on('close', () => closed = true);
    await browser.close();
    expect(closed).toBe(true);
  });
});

describe('browserType.launch |webSocket| option', function() {
  it('should support the webSocket option', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const browserContext = await browser.newContext();
    expect(browserContext.pages().length).toBe(0);
    expect(browserServer.wsEndpoint()).not.toBe(null);
    const page = await browserContext.newPage();
    expect(await page.evaluate('11 * 11')).toBe(121);
    await page.close();
    await browser.close();
    await browserServer._checkLeaks();
    await browserServer.close();
  });
  it('should fire "disconnected" when closing with webSocket', async({browserType, defaultBrowserOptions}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
    const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
    const closedPromise = new Promise(f => browserServer.on('close', f));
    browserServer.kill();
    await Promise.all([
      disconnectedEventPromise,
      closedPromise,
    ]);
  });
});

describe('browserType.connect', function() {
  it.slow()('should be able to reconnect to a browser', async({browserType, defaultBrowserOptions, server}) => {
    const browserServer = await browserType.launchServer(defaultBrowserOptions);
    {
      const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
      const browserContext = await browser.newContext();
      const page = await browserContext.newPage();
      await page.goto(server.EMPTY_PAGE);
      await browser.close();
    }
    {
      const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
      const browserContext = await browser.newContext();
      const page = await browserContext.newPage();
      await page.goto(server.EMPTY_PAGE);
      await browser.close();
    }
    await browserServer._checkLeaks();
    await browserServer.close();
  });
});

describe('browserType.launchPersistentContext', function() {
  it('userDataDir option', async({browserType, defaultBrowserOptions}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    // Open a page to make sure its functional.
    await browserContext.newPage();
    expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
    await browserContext.close();
    expect(fs.readdirSync(userDataDir).length).toBeGreaterThan(0);
    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
  });
  it.slow()('userDataDir option should restore state', async({browserType, defaultBrowserOptions, server}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page = await browserContext.newPage();
    await page.goto(server.EMPTY_PAGE);
    await page.evaluate(() => localStorage.hey = 'hello');
    await browserContext.close();

    const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page2 = await browserContext2.newPage();
    await page2.goto(server.EMPTY_PAGE);
    expect(await page2.evaluate(() => localStorage.hey)).toBe('hello');
    await browserContext2.close();

    const userDataDir2 = await makeUserDataDir();
    const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions);
    const page3 = await browserContext3.newPage();
    await page3.goto(server.EMPTY_PAGE);
    expect(await page3.evaluate(() => localStorage.hey)).not.toBe('hello');
    await browserContext3.close();

    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
    await removeUserDataDir(userDataDir2);
  });
  // TODO: Flaky! See https://github.com/microsoft/playwright/pull/1795/checks?check_run_id=587685496
  it.slow().fail(WIN && CHROMIUM)('userDataDir option should restore cookies', async({browserType, defaultBrowserOptions,  server}) => {
    const userDataDir = await makeUserDataDir();
    const browserContext = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page = await browserContext.newPage();
    await page.goto(server.EMPTY_PAGE);
    await page.evaluate(() => document.cookie = 'doSomethingOnlyOnce=true; expires=Fri, 31 Dec 9999 23:59:59 GMT');
    await browserContext.close();

    const browserContext2 = await browserType.launchPersistentContext(userDataDir, defaultBrowserOptions);
    const page2 = await browserContext2.newPage();
    await page2.goto(server.EMPTY_PAGE);
    expect(await page2.evaluate(() => document.cookie)).toBe('doSomethingOnlyOnce=true');
    await browserContext2.close();

    const userDataDir2 = await makeUserDataDir();
    const browserContext3 = await browserType.launchPersistentContext(userDataDir2, defaultBrowserOptions);
    const page3 = await browserContext3.newPage();
    await page3.goto(server.EMPTY_PAGE);
    expect(await page3.evaluate(() => localStorage.hey)).not.toBe('doSomethingOnlyOnce=true');
    await browserContext3.close();

    // This might throw. See https://github.com/GoogleChrome/puppeteer/issues/2778
    await removeUserDataDir(userDataDir);
    await removeUserDataDir(userDataDir2);
  });
});
<|endoftext|>


<commit_before>// NOTE: run this test independently as
// npm test test/lib/container.js

require('co-mocha');
var sinon = require('sinon');
var Promise = require('bluebird');

var child_process = require('child_process');

var Container = require('../../lib/Container');

//require('nock').restore()

describe.skip('Container', function() {
  describe('events', function() {
    it('fires a generic stateChange event', function(done) {
      var container = new Container({});

      var event = sinon.spy();
      var stateChange = function() {
        event.called.should.be.ok;

        var args = Array.prototype.slice.call(arguments);
        args.should.eql(['stopping']);

        done();
      };

      container.on('stopping', event);
      container.on('stateChange', stateChange);

      // stub out stop method on internal container
      container.container = {stop: sinon.spy()};

      container.stop();
    });
  });

  describe('stats', function() {
    var container, containerInfo;

    before(function*() {
      container = new Container({
        docker: {
          socketPath: '/var/run/docker.sock'
        },
        image: 'proboci/ubuntu-14.04-lamp',
        imageConfig: {
          'proboci/ubuntu-14.04-lamp': {
            services: []
          }
        },
        build: {
          ref: null,
          id: null
        }
      });

      Promise.promisifyAll(container);

      // will start the container too
      containerInfo = yield container.create();
      container.containerId = containerInfo.Id;
    });

    after(function*() {
      yield container.remove({force: true});
    });

    it('image size', function* () {
      var size = yield container.imageSizeAsync(containerInfo.Image);
      size.should.be.a.Number;
    });

    it('container size', function* () {
      // test 1: make sure execing and parsing works
      var stubs = sinon.stub(child_process, 'exec').yields(null, '123 /var/lib/...', '');
      try {
        var size = yield container.containerSizeAsync();
        size.should.be.a.Number;
      }
      finally {
        stubs.restore();
      }

      // test 2: error handling
      try {
        yield container.containerSizeAsync();
        throw new Error('Should not get here');
      } catch (e) {
        e.message.should.eql(`Command failed: /bin/sh -c du -bs /var/lib/docker/aufs/diff/${container.containerId}\ndu: cannot access ‘/var/lib/docker/aufs/diff/${container.containerId}’: Permission denied\n`);
      }

    });
  });
});
<commit_msg>don't skip container events test<commit_after>// NOTE: run this test independently as
// npm test test/lib/container.js

require('co-mocha');
var sinon = require('sinon');
var Promise = require('bluebird');

var child_process = require('child_process');

var Container = require('../../lib/Container');

//require('nock').restore()

describe('Container', function() {
  describe('events', function() {
    it('fires a generic stateChange event', function(done) {
      var container = new Container({});

      var event = sinon.spy();
      var stateChange = function() {
        event.called.should.be.ok;

        var args = Array.prototype.slice.call(arguments);
        args.should.eql(['stopping']);

        done();
      };

      container.on('stopping', event);
      container.on('stateChange', stateChange);

      // stub out stop method on internal container
      container.container = {stop: sinon.spy()};

      container.stop();
    });
  });

  describe.skip('stats', function() {
    var container, containerInfo;

    before(function*() {
      container = new Container({
        docker: {
          socketPath: '/var/run/docker.sock'
        },
        image: 'proboci/ubuntu-14.04-lamp',
        imageConfig: {
          'proboci/ubuntu-14.04-lamp': {
            services: []
          }
        },
        build: {
          ref: null,
          id: null
        }
      });

      Promise.promisifyAll(container);

      // will start the container too
      containerInfo = yield container.create();
      container.containerId = containerInfo.Id;
    });

    after(function*() {
      yield container.remove({force: true});
    });

    it('image size', function* () {
      var size = yield container.imageSizeAsync(containerInfo.Image);
      size.should.be.a.Number;
    });

    it('container size', function* () {
      // test 1: make sure execing and parsing works
      var stubs = sinon.stub(child_process, 'exec').yields(null, '123 /var/lib/...', '');
      try {
        var size = yield container.containerSizeAsync();
        size.should.be.a.Number;
      }
      finally {
        stubs.restore();
      }

      // test 2: error handling
      try {
        yield container.containerSizeAsync();
        throw new Error('Should not get here');
      } catch (e) {
        e.message.should.eql(`Command failed: /bin/sh -c du -bs /var/lib/docker/aufs/diff/${container.containerId}\ndu: cannot access ‘/var/lib/docker/aufs/diff/${container.containerId}’: Permission denied\n`);
      }

    });
  });
});
<|endoftext|>