<commit_before>import React from 'react';
import moment from 'moment';
// import 'moment/locale/no';
import classNames from 'classnames';
// import Popup from '../Popup';
import ActionButton from '../ActionButton';
import Typography from '../Typography';
import ButtonCounter from '../ButtonCounter';
import Wrapper from '../Wrapper';
import Spacer from '../Spacer';
import styles from './styles.css';

class PopoverCalendar extends React.Component {
  constructor(props) {
    super(props);
    const duckyCalendar = {
      Language: moment.locale(this.props.language)
    };

    console.log('thispropslanguage: ', this.props.language);
    console.log('duckyCalendar: ', duckyCalendar);
    console.log('current locale:', moment.localeData());
  }

/*
  // Days in week constructor:

  structDays = function() {
    const thisIsTheDays = [M,T,O,T,F,L,S];
    let index = 0;
    const Day = thisIsTheDays[index];
    const daysInWeek = thisIsTheDays.length;
*/
  structWeek() {
    let week = [];
    week = moment.months();
    const daysInWeek = week.length();
    const rows = [];

    for (let index = 0; index <= daysInWeek; index += 1) {
      rows.push(<ButtonCounter number={this.days.inWeek[index]} />
      );
    }
    return (<Wrapper size="slender">{rows}</Wrapper>);
  }
  render() {
    const arrowLeft = 'icon-arrow_back';
    const arrowRight = 'icon-arrow_forward';

    return (
      <Wrapper className={classNames(styles.wrapper, {[this.props.className]: this.props.className})}
        size="standard"
        >

          <ActionButton className={styles.icon}
            icon={arrowLeft}
            />
          <Typography className={styles.month}> {this.props.month} </Typography>
          <Typography className={styles.year}> {this.props.year} </Typography>
          <ActionButton className={styles.icon}
            icon={arrowRight}
            />

<Spacer size="double" />

          {this.structWeek()}

      </Wrapper>
    );
  }

  /* !!Just temporary made the bunch of buttonCounters manually, cause struct function will be have to be done different */
}
PopoverCalendar.propTypes = {
  // arrowLeft: React.PropTypes.shape(icon-arrow_back),
  // arrowRight: React.PropTypes.shape(icon-arrow_forward),
  children: React.PropTypes.node,
  className: React.PropTypes.string,
  language: React.PropTypes.string,
  // color: React.PropTypes.string,
  month: React.PropTypes.string,
  onClick: React.PropTypes.func,
  // style: React.PropTypes.shape({}),
  structWeek: React.PropTypes.func,
  year: React.PropTypes.number

};
export default PopoverCalendar;
<commit_msg>Added language reference by import. now norwegian become default for time/date preferences.<commit_after>import React from 'react';
import moment from 'moment';
import norsk from 'moment/locale/nb';
/* Linking the nb.js in my main project file automatically changed the locale for all accesses to the moment class and its methods.
There will be no need anymore to do a moment.locale("nb"). or moment.lang("nb"). in the source code. */
import classNames from 'classnames';
// import Popup from '../Popup';
import ActionButton from '../ActionButton';
import Typography from '../Typography';
import ButtonCounter from '../ButtonCounter';
import Wrapper from '../Wrapper';
import Spacer from '../Spacer';
import styles from './styles.css';

class PopoverCalendar extends React.Component {
  constructor(props) {
    super(props);
    const duckyCalendar = {
      Language: this.props.language
    };
    // let norsk = moment.locale("de").format("LLL");

    console.log('thispropslanguage: ', this.props.language);
    console.log('duckyCalendar: ', duckyCalendar);
    // console.log('current locale:', moment.localeData());
  }

/*
  // Days in week constructor:

  structDays = function() {
    const thisIsTheDays = [M,T,O,T,F,L,S];
    let index = 0;
    const Day = thisIsTheDays[index];
    const daysInWeek = thisIsTheDays.length;
*/
  structWeek() {
    let week = [];
    moment.format('ll');
    // moment.locale("de").format("LLL");
    console.log(moment.startOf('week'));
    week = moment.weekdays();
    console.log('week/moment.months: ', week, moment.weekdaysShort);
    const daysInWeek = week.length;

    console.log('days in week: ', daysInWeek);
    const rows = [];

    for (let index = 0; index < daysInWeek; index += 1) {
      rows.push(<ButtonCounter number={daysInWeek[index]} />
      );
    }
    return (<Wrapper size="slender">{rows}</Wrapper>);
  }
  render() {
    const arrowLeft = 'icon-arrow_back';
    const arrowRight = 'icon-arrow_forward';

    return (
      <Wrapper className={classNames(styles.wrapper, {[this.props.className]: this.props.className})}
        size="standard"
        >

          <ActionButton className={styles.icon}
            icon={arrowLeft}
            />
          <Typography className={styles.month}> {this.props.month} </Typography>
          <Typography className={styles.year}> {this.props.year} </Typography>
          <ActionButton className={styles.icon}
            icon={arrowRight}
            />

<Spacer size="double" />

          {this.structWeek()}

      </Wrapper>
    );
  }

}
PopoverCalendar.propTypes = {
  // arrowLeft: React.PropTypes.shape(icon-arrow_back),
  // arrowRight: React.PropTypes.shape(icon-arrow_forward),
  children: React.PropTypes.node,
  className: React.PropTypes.string,
  language: React.PropTypes.string,
  // color: React.PropTypes.string,
  month: React.PropTypes.string,
  onClick: React.PropTypes.func,
  // style: React.PropTypes.shape({}),
  structWeek: React.PropTypes.func,
  year: React.PropTypes.number

};
export default PopoverCalendar;
<|endoftext|>


<commit_before>/**
 * Copyright 2018 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.
 */

/**
 * @type {PageTestSuite}
 */
module.exports.describe = function({testRunner, expect, playwright, headless, FFOX, CHROMIUM, WEBKIT}) {
  const {describe, xdescribe, fdescribe} = testRunner;
  const {it, fit, xit, dit} = testRunner;
  const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
  const iPhone = playwright.devices['iPhone 6'];
  const iPhoneLandscape = playwright.devices['iPhone 6 landscape'];

  describe('Page.viewport', function() {
    it('should get the proper viewport size', async({page, server}) => {
      expect(page.viewportSize()).toEqual({width: 800, height: 600});
      await page.setViewportSize({width: 123, height: 456});
      expect(page.viewportSize()).toEqual({width: 123, height: 456});
    });
    it('should support mobile emulation', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(375);
      await page.setViewportSize({width: 400, height: 300});
      expect(await page.evaluate(() => window.innerWidth)).toBe(400);
    });
    it('should not have touch by default', async({page, server}) => {
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(false);
      await page.goto(server.PREFIX + '/detect-touch.html');
      expect(await page.evaluate(() => document.body.textContent.trim())).toBe('NO');
    });
    it('should support touch emulation', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true);
      expect(await page.evaluate(dispatchTouch)).toBe('Received touch');

      function dispatchTouch() {
        let fulfill;
        const promise = new Promise(x => fulfill = x);
        window.ontouchstart = function(e) {
          fulfill('Received touch');
        };
        window.dispatchEvent(new Event('touchstart'));

        fulfill('Did not receive touch');

        return promise;
      }
    });
    it('should be detectable by Modernizr', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/detect-touch.html');
      expect(await page.evaluate(() => document.body.textContent.trim())).toBe('YES');
    });
    it('should detect touch when applying viewport with touches', async({newContext, server}) => {
      const context = await newContext({ viewport: { width: 800, height: 600, isMobile: true } });
      const page = await context.newPage();
      await page.goto(server.EMPTY_PAGE);
      await page.addScriptTag({url: server.PREFIX + '/modernizr.js'});
      expect(await page.evaluate(() => Modernizr.touchevents)).toBe(true);
    });
    it.skip(FFOX)('should support landscape emulation', async({newContext, server}) => {
      const context1 = await newContext({ viewport: iPhone.viewport });
      const page1 = await context1.newPage();
      await page1.goto(server.PREFIX + '/mobile.html');
      expect(await page1.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(false);
      const context2 = await newContext({ viewport: iPhoneLandscape.viewport });
      const page2 = await context2.newPage();
      expect(await page2.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(true);
    });
    it.skip(FFOX || WEBKIT)('should fire orientationchange event', async({newContext, server}) => {
      const context = await newContext({ viewport: { width: 300, height: 400, isMobile: true } });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      await page.evaluate(() => {
        window.counter = 0;
        window.addEventListener('orientationchange', () => console.log(++window.counter));
      });

      const event1 = page.waitForEvent('console');
      await page.setViewportSize({width: 400, height: 300});
      expect((await event1).text()).toBe('1');

      const event2 = page.waitForEvent('console');
      await page.setViewportSize({width: 300, height: 400});
      expect((await event2).text()).toBe('2');
    });
    it.skip(FFOX)('default mobile viewports to 980 width', async({newContext, server}) => {
      const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/empty.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(980);
    });
    it.skip(FFOX)('respect meta viewport tag', async({newContext, server}) => {
      const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(320);
    });
  });

  describe('Page.emulate', function() {
    it('should work', async({newPage, server}) => {
      const page = await newPage({ viewport: iPhone.viewport, userAgent: iPhone.userAgent });
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(375);
      expect(await page.evaluate(() => navigator.userAgent)).toContain('iPhone');
    });
    it('should support clicking', async({newPage, server}) => {
      const page = await newPage({ viewport: iPhone.viewport, userAgent: iPhone.userAgent });
      await page.goto(server.PREFIX + '/input/button.html');
      const button = await page.$('button');
      await page.evaluate(button => button.style.marginTop = '200px', button);
      await button.click();
      expect(await page.evaluate(() => result)).toBe('Clicked');
    });
  });

  describe('Page.emulateMedia type', function() {
    it('should work', async({page, server}) => {
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
      await page.emulateMedia({ media: 'print' });
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
      await page.emulateMedia({});
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
      await page.emulateMedia({ media: '' });
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
    });
    it('should throw in case of bad type argument', async({page, server}) => {
      let error = null;
      await page.emulateMedia({ media: 'bad' }).catch(e => error = e);
      expect(error.message).toBe('Unsupported media: bad');
    });
  });

  describe('Page.emulateMedia colorScheme', function() {
    it('should work', async({page, server}) => {
      await page.emulateMedia({ colorScheme: 'light' });
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
      await page.emulateMedia({ colorScheme: 'dark' });
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
      if (!WEBKIT) {
        // WebKit will always provide the value.
        await page.emulateMedia({ colorScheme: 'no-preference' });
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(true);
      }
    });
    it('should throw in case of bad argument', async({page, server}) => {
      let error = null;
      await page.emulateMedia({ colorScheme: 'bad' }).catch(e => error = e);
      expect(error.message).toBe('Unsupported color scheme: bad');
    });
    it.skip(FFOX)('should work during navigation', async({page, server}) => {
      await page.emulateMedia({ colorScheme: 'light' });
      const navigated = page.goto(server.EMPTY_PAGE);
      for (let i = 0; i < 9; i++) {
        await Promise.all([
          page.emulateMedia({ colorScheme: ['dark', 'light'][i & 1] }),
          new Promise(f => setTimeout(f, 1)),
        ]);
      }
      await navigated;
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
    });
  });

  describe.skip(FFOX)('BrowserContext({timezoneId})', function() {
    it('should work', async ({ newPage }) => {
      const func = () => new Date(1479579154987).toString();
      {
        const page = await newPage({ timezoneId: 'America/Jamaica' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 13:12:34 GMT-0500 (Eastern Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'Pacific/Honolulu' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 08:12:34 GMT-1000 (Hawaii-Aleutian Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'America/Buenos_Aires' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 15:12:34 GMT-0300 (Argentina Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'Europe/Berlin' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 19:12:34 GMT+0100 (Central European Standard Time)');
      }
    });

    it('should throw for invalid timezone IDs', async({newPage}) => {
      let error = null;
      await newPage({ timezoneId: 'Foo/Bar' }).catch(e => error = e);
      expect(error.message).toBe('Invalid timezone ID: Foo/Bar');
      await newPage({ timezoneId: 'Baz/Qux' }).catch(e => error = e);
      expect(error.message).toBe('Invalid timezone ID: Baz/Qux');
    });
  });

  describe.skip(CHROMIUM || FFOX)('BrowserContext({language})', function() {
    it('should affect accept-language header', async({newPage, server}) => {
      const page = await newPage({ locale: 'fr-CH' });
      const [request] = await Promise.all([
        server.waitForRequest('/empty.html'),
        page.goto(server.EMPTY_PAGE),
      ]);
      expect(request.headers['accept-language']).toBe('fr-CH');
      expect(await page.evaluate(() => navigator.language)).toBe('fr-CH');
    });
    it('should format number', async({newPage, server}) => {
      {
        const page = await newPage();
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe('1,000,000.5');
      }
      {
        const page = await newPage({ locale: 'fr-CH' });
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe('1 000 000,5');
      }
    });
    it('should format date', async({newPage, server}) => {
      {
        const page = await newPage();
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe(
            'Sat Nov 19 2016 10:12:34 GMT-0800 (PST)');
      }
      {
        const page = await newPage({ locale: 'de-de', timezoneId: 'Europe/Berlin' });
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe(
            'Sat Nov 19 2016 19:12:34 GMT+0100 (Mitteleuropäische Normalzeit)');
      }
    });
  });

  describe('focus', function() {
    it.skip(!headless)('should think that it is focused by default', async({page}) => {
      expect(await page.evaluate('document.hasFocus()')).toBe(true);
    });
  });
};
<commit_msg>test: fix locale expectations on non-Mac (#994)<commit_after>/**
 * Copyright 2018 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.
 */

/**
 * @type {PageTestSuite}
 */
module.exports.describe = function({testRunner, expect, playwright, headless, FFOX, CHROMIUM, WEBKIT, MAC, WIN}) {
  const {describe, xdescribe, fdescribe} = testRunner;
  const {it, fit, xit, dit} = testRunner;
  const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
  const iPhone = playwright.devices['iPhone 6'];
  const iPhoneLandscape = playwright.devices['iPhone 6 landscape'];

  describe('Page.viewport', function() {
    it('should get the proper viewport size', async({page, server}) => {
      expect(page.viewportSize()).toEqual({width: 800, height: 600});
      await page.setViewportSize({width: 123, height: 456});
      expect(page.viewportSize()).toEqual({width: 123, height: 456});
    });
    it('should support mobile emulation', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(375);
      await page.setViewportSize({width: 400, height: 300});
      expect(await page.evaluate(() => window.innerWidth)).toBe(400);
    });
    it('should not have touch by default', async({page, server}) => {
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(false);
      await page.goto(server.PREFIX + '/detect-touch.html');
      expect(await page.evaluate(() => document.body.textContent.trim())).toBe('NO');
    });
    it('should support touch emulation', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => 'ontouchstart' in window)).toBe(true);
      expect(await page.evaluate(dispatchTouch)).toBe('Received touch');

      function dispatchTouch() {
        let fulfill;
        const promise = new Promise(x => fulfill = x);
        window.ontouchstart = function(e) {
          fulfill('Received touch');
        };
        window.dispatchEvent(new Event('touchstart'));

        fulfill('Did not receive touch');

        return promise;
      }
    });
    it('should be detectable by Modernizr', async({newContext, server}) => {
      const context = await newContext({ viewport: iPhone.viewport });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/detect-touch.html');
      expect(await page.evaluate(() => document.body.textContent.trim())).toBe('YES');
    });
    it('should detect touch when applying viewport with touches', async({newContext, server}) => {
      const context = await newContext({ viewport: { width: 800, height: 600, isMobile: true } });
      const page = await context.newPage();
      await page.goto(server.EMPTY_PAGE);
      await page.addScriptTag({url: server.PREFIX + '/modernizr.js'});
      expect(await page.evaluate(() => Modernizr.touchevents)).toBe(true);
    });
    it.skip(FFOX)('should support landscape emulation', async({newContext, server}) => {
      const context1 = await newContext({ viewport: iPhone.viewport });
      const page1 = await context1.newPage();
      await page1.goto(server.PREFIX + '/mobile.html');
      expect(await page1.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(false);
      const context2 = await newContext({ viewport: iPhoneLandscape.viewport });
      const page2 = await context2.newPage();
      expect(await page2.evaluate(() => matchMedia('(orientation: landscape)').matches)).toBe(true);
    });
    it.skip(FFOX || WEBKIT)('should fire orientationchange event', async({newContext, server}) => {
      const context = await newContext({ viewport: { width: 300, height: 400, isMobile: true } });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      await page.evaluate(() => {
        window.counter = 0;
        window.addEventListener('orientationchange', () => console.log(++window.counter));
      });

      const event1 = page.waitForEvent('console');
      await page.setViewportSize({width: 400, height: 300});
      expect((await event1).text()).toBe('1');

      const event2 = page.waitForEvent('console');
      await page.setViewportSize({width: 300, height: 400});
      expect((await event2).text()).toBe('2');
    });
    it.skip(FFOX)('default mobile viewports to 980 width', async({newContext, server}) => {
      const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/empty.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(980);
    });
    it.skip(FFOX)('respect meta viewport tag', async({newContext, server}) => {
      const context = await newContext({ viewport: {width: 320, height: 480, isMobile: true} });
      const page = await context.newPage();
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(320);
    });
  });

  describe('Page.emulate', function() {
    it('should work', async({newPage, server}) => {
      const page = await newPage({ viewport: iPhone.viewport, userAgent: iPhone.userAgent });
      await page.goto(server.PREFIX + '/mobile.html');
      expect(await page.evaluate(() => window.innerWidth)).toBe(375);
      expect(await page.evaluate(() => navigator.userAgent)).toContain('iPhone');
    });
    it('should support clicking', async({newPage, server}) => {
      const page = await newPage({ viewport: iPhone.viewport, userAgent: iPhone.userAgent });
      await page.goto(server.PREFIX + '/input/button.html');
      const button = await page.$('button');
      await page.evaluate(button => button.style.marginTop = '200px', button);
      await button.click();
      expect(await page.evaluate(() => result)).toBe('Clicked');
    });
  });

  describe('Page.emulateMedia type', function() {
    it('should work', async({page, server}) => {
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
      await page.emulateMedia({ media: 'print' });
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
      await page.emulateMedia({});
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(true);
      await page.emulateMedia({ media: '' });
      expect(await page.evaluate(() => matchMedia('screen').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('print').matches)).toBe(false);
    });
    it('should throw in case of bad type argument', async({page, server}) => {
      let error = null;
      await page.emulateMedia({ media: 'bad' }).catch(e => error = e);
      expect(error.message).toBe('Unsupported media: bad');
    });
  });

  describe('Page.emulateMedia colorScheme', function() {
    it('should work', async({page, server}) => {
      await page.emulateMedia({ colorScheme: 'light' });
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
      await page.emulateMedia({ colorScheme: 'dark' });
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(false);
      if (!WEBKIT) {
        // WebKit will always provide the value.
        await page.emulateMedia({ colorScheme: 'no-preference' });
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: light)').matches)).toBe(false);
        expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches)).toBe(true);
      }
    });
    it('should throw in case of bad argument', async({page, server}) => {
      let error = null;
      await page.emulateMedia({ colorScheme: 'bad' }).catch(e => error = e);
      expect(error.message).toBe('Unsupported color scheme: bad');
    });
    it.skip(FFOX)('should work during navigation', async({page, server}) => {
      await page.emulateMedia({ colorScheme: 'light' });
      const navigated = page.goto(server.EMPTY_PAGE);
      for (let i = 0; i < 9; i++) {
        await Promise.all([
          page.emulateMedia({ colorScheme: ['dark', 'light'][i & 1] }),
          new Promise(f => setTimeout(f, 1)),
        ]);
      }
      await navigated;
      expect(await page.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
    });
  });

  describe.skip(FFOX)('BrowserContext({timezoneId})', function() {
    it('should work', async ({ newPage }) => {
      const func = () => new Date(1479579154987).toString();
      {
        const page = await newPage({ timezoneId: 'America/Jamaica' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 13:12:34 GMT-0500 (Eastern Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'Pacific/Honolulu' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 08:12:34 GMT-1000 (Hawaii-Aleutian Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'America/Buenos_Aires' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 15:12:34 GMT-0300 (Argentina Standard Time)');
      }
      {
        const page = await newPage({ timezoneId: 'Europe/Berlin' });
        expect(await page.evaluate(func)).toBe('Sat Nov 19 2016 19:12:34 GMT+0100 (Central European Standard Time)');
      }
    });

    it('should throw for invalid timezone IDs', async({newPage}) => {
      let error = null;
      await newPage({ timezoneId: 'Foo/Bar' }).catch(e => error = e);
      expect(error.message).toBe('Invalid timezone ID: Foo/Bar');
      await newPage({ timezoneId: 'Baz/Qux' }).catch(e => error = e);
      expect(error.message).toBe('Invalid timezone ID: Baz/Qux');
    });
  });

  describe.skip(CHROMIUM || FFOX)('BrowserContext({language})', function() {
    it('should affect accept-language header', async({newPage, server}) => {
      const page = await newPage({ locale: 'fr-CH' });
      const [request] = await Promise.all([
        server.waitForRequest('/empty.html'),
        page.goto(server.EMPTY_PAGE),
      ]);
      expect(request.headers['accept-language'].substr(0, 5)).toBe('fr-CH');
    });
    it('should affect navigator.language', async({newPage, server}) => {
      const page = await newPage({ locale: 'fr-CH' });
      expect(await page.evaluate(() => navigator.language)).toBe('fr-CH');
    });
    it('should format number', async({newPage, server}) => {
      {
        const page = await newPage();
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe('1,000,000.5');
      }
      {
        const page = await newPage({ locale: 'fr-CH' });
        await page.goto(server.EMPTY_PAGE);
        const formatted = MAC ? '1\u00A0000\u00A0000,5' : '1\u202F000\u202F000,5';
        expect(await page.evaluate(() => (1000000.50).toLocaleString())).toBe(formatted);
      }
    });
    it('should format date', async({newPage, server}) => {
      {
        const page = await newPage();
        await page.goto(server.EMPTY_PAGE);
        const formatted = WIN ? 'Sat Nov 19 2016 10:12:34 GMT-0800 (Pacific Standard Time)' : 'Sat Nov 19 2016 10:12:34 GMT-0800 (PST)';
        expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe(formatted);
      }
      {
        const page = await newPage({ locale: 'de-de', timezoneId: 'Europe/Berlin' });
        await page.goto(server.EMPTY_PAGE);
        expect(await page.evaluate(() => new Date(1479579154987).toString())).toBe(
            'Sat Nov 19 2016 19:12:34 GMT+0100 (Mitteleuropäische Normalzeit)');
      }
    });
  });

  describe('focus', function() {
    it.skip(!headless)('should think that it is focused by default', async({page}) => {
      expect(await page.evaluate('document.hasFocus()')).toBe(true);
    });
  });
};
<|endoftext|>


<commit_before>/* global suite, test */
( function() {
    "use strict";

    var assert = require( 'assert' );

    var vscode = require( 'vscode' );
    var myExtension = require( '../extension' );
    var commands = require( '../src/commands' );
    var Range = vscode.Range;
    let path = require( 'path' );
    let editorHelpers = require( './_helpers/editor' );

    suite( 'commamnds.moveRight', function() {
        test( 'Move within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 0 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move within same text case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 1 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move within camel case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIs^ACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 4 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move over whitespace', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIsACamelCaseWord itsSuperFun   ^to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 32, 0, 32 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( 'commamnds.moveLeft', function() {
        test( 'Move within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 6, 0, 6 );

                    commands.moveLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move from just after capitalized', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 5, 0, 5 );

                    commands.moveLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( 'commamnds.selectRight', function() {
        test( 'Expand within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[this}IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 0 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within same text case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[this}IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 1 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within camel case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[thisIs}ACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 4 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( '_getCharType', function() {
        test( '_getCharType', function() {
            let testValue = ( expected, valueUsed ) => {
                assert.strictEqual( commands._getCharType( valueUsed ), expected, valueUsed );
            }

            testValue( 3, 'a' );
            testValue( 3, 'aBC' );
            testValue( 2, 'B' );
            testValue( 2, 'Bac' );
            testValue( 1, '0' );
            testValue( 1, '-'  );
            testValue( 1, ' '  );
            testValue( 1, ''  );
        } )
    } )
} )();<commit_msg>Added tests for selectLeft command.<commit_after>/* global suite, test */
( function() {
    "use strict";

    var assert = require( 'assert' );

    var vscode = require( 'vscode' );
    var myExtension = require( '../extension' );
    var commands = require( '../src/commands' );
    var Range = vscode.Range;
    let path = require( 'path' );
    let editorHelpers = require( './_helpers/editor' );

    suite( 'commands.moveRight', function() {
        test( 'Move within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 0 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move within same text case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 1 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move within camel case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIs^ACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 4 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move over whitespace', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIsACamelCaseWord itsSuperFun   ^to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 32, 0, 32 );

                    commands.moveRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( 'commands.moveLeft', function() {
        test( 'Move within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 6, 0, 6 );

                    commands.moveLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Move from just after capitalized', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'this^IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 5, 0, 5 );

                    commands.moveLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( 'commands.selectRight', function() {
        test( 'Expand within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[this}IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 0 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within same text case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[this}IsACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 1 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within camel case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = '[thisIs}ACamelCaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 0, 0, 4 );

                    commands.selectRight( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( 'commands.selectLeft', function() {
        test( 'Expand within same text case collapsed', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIsA{Camel]CaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 12, 0, 12 );

                    commands.selectLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within same text case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIsA{Camel]CaseWord itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 12, 0, 10 );

                    commands.selectLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );

        test( 'Expand within camel case ranged', function() {
            return vscode.workspace.openTextDocument( path.join( __dirname, '_fixtures', 'camelCase.txt' ) )
                .then( ( doc ) => {
                    return vscode.window.showTextDocument( doc );
                } )
                .then( textEditor => {
                    let expected = 'thisIsACamel{CaseWord] itsSuperFun   to	writeIn-CamelCase\n' +
                        'you could also mix it with12345wordsToSee how it behaves with numbers';
                    textEditor.selection = new vscode.Selection( 0, 20, 0, 16 );

                    commands.selectLeft( textEditor );

                    assert.equal( editorHelpers.getContentWithSelections( textEditor ), expected );
                } );
        } );
    } );

    suite( '_getCharType', function() {
        test( '_getCharType', function() {
            let testValue = ( expected, valueUsed ) => {
                assert.strictEqual( commands._getCharType( valueUsed ), expected, valueUsed );
            }

            testValue( 3, 'a' );
            testValue( 3, 'aBC' );
            testValue( 2, 'B' );
            testValue( 2, 'Bac' );
            testValue( 1, '0' );
            testValue( 1, '-'  );
            testValue( 1, ' '  );
            testValue( 1, ''  );
        } )
    } )
} )();<|endoftext|>


<commit_before>let puppeteer = require('puppeteer'),
    assert    = require('assert'),
    Hawkejs   = require('../../index.js'),
    http      = require('http'),
    fs        = require('fs');

let navigations = 0,
    coverages = [];

global.do_coverage = !!global.__coverage__;
global.page = null;

let hserverside_rx = /hserverside-\d+/g,
    hrendered_rx = /he-rendered="\d+?"/i;

global.createHawkejsInstance = function createHawkejsInstance() {

	let hawkejs = new Hawkejs();

	// Disable the exposed static variables being loaded via separate js file
	hawkejs.exposed_path = null;

	return hawkejs;
};

/**
 * Normalize attributes that are randomly generated
 */
global.assertEqualHtml = function assertEqualHtml(actual, expected, message) {

	actual = despace(actual);
	expected = despace(expected);

	// Normalize he-rendered attributes
	actual = actual.replace(hrendered_rx, 'he-rendered="1"');
	expected = expected.replace(hrendered_rx, 'he-rendered="1"');

	actual = actual.replace(hserverside_rx, 'hserverside-0');
	expected = expected.replace(hserverside_rx, 'hserverside-0');

	return assert.strictEqual(actual, expected, message);
};

global.fetchCoverage = async function fetchCoverage() {

	if (!page) {
		return;
	}

	let temp = await page.evaluate(function getCoverage() {
		return window.__coverage__;
	});

	if (temp) {
		coverages.push(temp);
	}

	return coverages;
};

global.setLocation = async function setLocation(path) {

	let url;

	if (!page) {
		await loadBrowser();
	}

	if (navigations && do_coverage) {
		await fetchCoverage();
	}

	navigations++;

	if (path.indexOf('http') == -1) {
		url = 'http://127.0.0.1:' + port + path;
	} else {
		url = path;
	}

	await page.goto(url);
};

global.clickPage = function clickPage(selector, options) {
	return page.click(selector, options);
};

global.evalPage = function evalPage(fnc, ...args) {
	return page.evaluate(fnc, ...args);
};

global.despace = function despace(text) {
	return text.trim().replace(/\n/g, ' ').replace(/\s\s+/g, ' ');
};

global.respondWithRender = function respondWithRender(templates, renderer, responder) {
	renderer.renderHTML(templates).done(function afterRender(err, html) {

		if (err != null) {
			throw err;
		}

		responder(html);
	});
}

global.actions = {};

// Click on a link & wait for hawkejs to render it
global.clickHeLink = async function clickHeLink(selector, options) {

	let wait_for_render = true;

	if (!wait_for_render) {
		return clickPage(selector, options);
	}

	let wait_for_open_url = evalPage(function() {
		let pledge = new __Protoblast.Classes.Pledge();

		hawkejs.scene.once('opened_url', function whenUrlOpened(href, err) {

			if (err) {
				return pledge.reject(err);
			}

			pledge.resolve(true);
		});

		return pledge;
	});

	await clickPage(selector, options);

	await wait_for_open_url;
}

global.openHeUrl = function openHeUrl(path) {
	return evalPage(function(path) {
		return hawkejs.scene.openUrl(path);
	}, path);
};

global.getBlockData = async function getBlockData(name) {

	if (!name) {
		name = 'main';
	}

	let result = await evalPage(function(name) {
		let block = document.querySelector('[data-he-name="' + name + '"]');

		let result = {
			name       : block.dataset.heName,
			template   : block.dataset.heTemplate,
			html       : block.outerHTML,
			text       : block.textContent,
			location   : document.location.pathname,
			scroll_top : document.scrollingElement.scrollTop,
		};

		return result;
	}, name);

	assert.strictEqual(result.name, name);

	return result;
};

global.scrollTo = async function scrollTo(selector) {

	let result = await evalPage(async function(selector) {

		let element = document.querySelector(selector);

		if (!element) {
			throw new Error('Could not find element by selector "' + selector + '"');
		}

		await hawkejs.scene.scrollTo(element);

		let container = element.getScrollContainer();

		let scroll_top = document.scrollingElement.scrollTop;

		let result = {
			container            : container.id,
			container_tag        : container.tagName,
			container_scroll_top : container.scrollTop,
			main_scroll_top      : document.scrollingElement.scrollTop,
			main_scroll_tag      : document.scrollingElement.tagName,
		};

		return result;
	}, selector);

	return result;
};

global.getHtml = async function getHtml() {

	return await evalPage(function() {

		let html = document.querySelector('html');

		return {
			html : html.outerHTML
		};
	});
};

global.loadHawkejs = function loadHawkejs() {

	if (global.hawkejs) {
		return global.hawkejs;
	}

	global.hawkejs = createHawkejsInstance();

	hawkejs.parallel_task_limit = 1;

	let base = __dirname + '/..';

	hawkejs.addViewDirectory(base + '/templates');
	hawkejs.load(base + '/helpers/assign_test.js');
	hawkejs.load(base + '/helpers/html_in_constructor.js');
	hawkejs.load(base + '/helpers/my_button.js');
	hawkejs.load(base + '/helpers/my_sync_span.js');
	hawkejs.load(base + '/helpers/my_text.js');
	hawkejs.load(base + '/helpers/retain_test.js');
	hawkejs.load(base + '/helpers/html_resolver.js');
	hawkejs.load(base + '/helpers/render_after_attributes.js');

}

global.loadBrowser = async function loadBrowser() {

	global.browser = await puppeteer.launch({
		headless : true
	});

	global.page = await browser.newPage();

	page.on('console', function(msg) {
		var pieces = ['[BROWSER]'],
		    args = msg.args(),
		    args;

		for (arg of args) {
			let remote = arg._remoteObject;

			if (remote.type == 'string') {
				pieces.push(remote.value);
			} else if (remote.subtype == 'node') {
				pieces.push('\x1b[1m\x1b[36m<' + remote.description + '>\x1b[0m');
				//console.log(remote.preview);
			} else if (remote.className) {
				pieces.push('\x1b[1m\x1b[33m{' + remote.type + ' ' + remote.className + '}\x1b[0m');
			} else if (remote.value != null) {
				pieces.push(remote.value);
			} else {
				pieces.push(remote);
			}
		}

		console.log(...pieces);
	});

	loadHawkejs();

	await new Promise(function(resolve, reject) {
		server = http.createServer(function onReq(req, res) {

			var url = __Protoblast.Classes.RURL.parse(req.url),
			    renderer = hawkejs.createRenderer(),
			    templates;

			req.renderer = renderer;
			renderer.prepare(req, res);
			renderer.internal('url', url);

			// End stylesheet requests with a generic valid response
			if (url.pathname.indexOf('.css') > -1) {
				return res.end('body{color: #101010}');
			}

			if (url.pathname == '/hawkejs/hawkejs-client.js') {

				__Protoblast.getClientPath({
					modify_prototypes : true,
					ua                : req.headers.useragent,
					enable_coverage   : do_coverage,
				}).done(function gotClientFile(err, path) {

					if (err) {
						throw err;
					}

					fs.createReadStream(path).pipe(res);
				});

				return;
			}

			// Serve multiple template files
			if (url.pathname == '/hawkejs/templates') {

				var names = url.param('name');

				if (!names) {
					res.status = 500;
					return res.end('No template names have been given');
				}

				hawkejs.getFirstAvailableSource(names, function gotResult(err, result) {

					if (err) {
						res.status = 500;
						return res.end(String(err));
					}

					if (!result || !result.name) {
						res.status = 400;
						return res.end('Could not find any of the given templates');
					}

					res.setHeader('content-type', 'application/json;charset=utf-8');
					res.end(JSON.stringify(result));
				});

				return;
			}

			if (actions[url.pathname]) {
				return actions[url.pathname](req, res, renderer, responder);
			}

			templates = url.pathname.slice(1);

			renderer.renderHTML(templates).done(function afterRender(err, html) {

				if (err != null) {
					throw err;
				}

				responder(html);
			});

			function responder(body, type) {

				if (!type) {
					if (typeof body !== 'string') {

						// Stringify using json-dry
						body = __Protoblast.Bound.JSON.dry(body);

						// Tell the client to expect a json-dry response
						type = 'application/json-dry';
					} else {
						type = 'text/html';
					}
				}

				// Only send the mimetype if it hasn't been set yet
				if (res.getHeader('content-type') == null) {
					res.setHeader('content-type', type + ";charset=utf-8");
				}

				res.end(body);
			}

		}).listen(0, '0.0.0.0', function listening() {
			port = server.address().port;
			resolve();
		});
	});
}<commit_msg>Fix despace method in unit tests not working on windows<commit_after>let puppeteer = require('puppeteer'),
    assert    = require('assert'),
    Hawkejs   = require('../../index.js'),
    http      = require('http'),
    fs        = require('fs');

let navigations = 0,
    coverages = [];

global.do_coverage = !!global.__coverage__;
global.page = null;

let hserverside_rx = /hserverside-\d+/g,
    hrendered_rx = /he-rendered="\d+?"/i;

global.createHawkejsInstance = function createHawkejsInstance() {

	let hawkejs = new Hawkejs();

	// Disable the exposed static variables being loaded via separate js file
	hawkejs.exposed_path = null;

	return hawkejs;
};

/**
 * Normalize attributes that are randomly generated
 */
global.assertEqualHtml = function assertEqualHtml(actual, expected, message) {

	actual = despace(actual);
	expected = despace(expected);

	// Normalize he-rendered attributes
	actual = actual.replace(hrendered_rx, 'he-rendered="1"');
	expected = expected.replace(hrendered_rx, 'he-rendered="1"');

	actual = actual.replace(hserverside_rx, 'hserverside-0');
	expected = expected.replace(hserverside_rx, 'hserverside-0');

	return assert.strictEqual(actual, expected, message);
};

global.fetchCoverage = async function fetchCoverage() {

	if (!page) {
		return;
	}

	let temp = await page.evaluate(function getCoverage() {
		return window.__coverage__;
	});

	if (temp) {
		coverages.push(temp);
	}

	return coverages;
};

global.setLocation = async function setLocation(path) {

	let url;

	if (!page) {
		await loadBrowser();
	}

	if (navigations && do_coverage) {
		await fetchCoverage();
	}

	navigations++;

	if (path.indexOf('http') == -1) {
		url = 'http://127.0.0.1:' + port + path;
	} else {
		url = path;
	}

	await page.goto(url);
};

global.clickPage = function clickPage(selector, options) {
	return page.click(selector, options);
};

global.evalPage = function evalPage(fnc, ...args) {
	return page.evaluate(fnc, ...args);
};

global.despace = function despace(text) {
	return text.trim().replace(/\r\n/g, ' ').replace(/\n/g, ' ').replace(/\s\s+/g, ' ');
};

global.respondWithRender = function respondWithRender(templates, renderer, responder) {
	renderer.renderHTML(templates).done(function afterRender(err, html) {

		if (err != null) {
			throw err;
		}

		responder(html);
	});
}

global.actions = {};

// Click on a link & wait for hawkejs to render it
global.clickHeLink = async function clickHeLink(selector, options) {

	let wait_for_render = true;

	if (!wait_for_render) {
		return clickPage(selector, options);
	}

	let wait_for_open_url = evalPage(function() {
		let pledge = new __Protoblast.Classes.Pledge();

		hawkejs.scene.once('opened_url', function whenUrlOpened(href, err) {

			if (err) {
				return pledge.reject(err);
			}

			pledge.resolve(true);
		});

		return pledge;
	});

	await clickPage(selector, options);

	await wait_for_open_url;
}

global.openHeUrl = function openHeUrl(path) {
	return evalPage(function(path) {
		return hawkejs.scene.openUrl(path);
	}, path);
};

global.getBlockData = async function getBlockData(name) {

	if (!name) {
		name = 'main';
	}

	let result = await evalPage(function(name) {
		let block = document.querySelector('[data-he-name="' + name + '"]');

		let result = {
			name       : block.dataset.heName,
			template   : block.dataset.heTemplate,
			html       : block.outerHTML,
			text       : block.textContent,
			location   : document.location.pathname,
			scroll_top : document.scrollingElement.scrollTop,
		};

		return result;
	}, name);

	assert.strictEqual(result.name, name);

	return result;
};

global.scrollTo = async function scrollTo(selector) {

	let result = await evalPage(async function(selector) {

		let element = document.querySelector(selector);

		if (!element) {
			throw new Error('Could not find element by selector "' + selector + '"');
		}

		await hawkejs.scene.scrollTo(element);

		let container = element.getScrollContainer();

		let scroll_top = document.scrollingElement.scrollTop;

		let result = {
			container            : container.id,
			container_tag        : container.tagName,
			container_scroll_top : container.scrollTop,
			main_scroll_top      : document.scrollingElement.scrollTop,
			main_scroll_tag      : document.scrollingElement.tagName,
		};

		return result;
	}, selector);

	return result;
};

global.getHtml = async function getHtml() {

	return await evalPage(function() {

		let html = document.querySelector('html');

		return {
			html : html.outerHTML
		};
	});
};

global.loadHawkejs = function loadHawkejs() {

	if (global.hawkejs) {
		return global.hawkejs;
	}

	global.hawkejs = createHawkejsInstance();

	hawkejs.parallel_task_limit = 1;

	let base = __dirname + '/..';

	hawkejs.addViewDirectory(base + '/templates');
	hawkejs.load(base + '/helpers/assign_test.js');
	hawkejs.load(base + '/helpers/html_in_constructor.js');
	hawkejs.load(base + '/helpers/my_button.js');
	hawkejs.load(base + '/helpers/my_sync_span.js');
	hawkejs.load(base + '/helpers/my_text.js');
	hawkejs.load(base + '/helpers/retain_test.js');
	hawkejs.load(base + '/helpers/html_resolver.js');
	hawkejs.load(base + '/helpers/render_after_attributes.js');

}

global.loadBrowser = async function loadBrowser() {

	global.browser = await puppeteer.launch({
		headless : true
	});

	global.page = await browser.newPage();

	page.on('console', function(msg) {
		var pieces = ['[BROWSER]'],
		    args = msg.args(),
		    args;

		for (arg of args) {
			let remote = arg._remoteObject;

			if (remote.type == 'string') {
				pieces.push(remote.value);
			} else if (remote.subtype == 'node') {
				pieces.push('\x1b[1m\x1b[36m<' + remote.description + '>\x1b[0m');
				//console.log(remote.preview);
			} else if (remote.className) {
				pieces.push('\x1b[1m\x1b[33m{' + remote.type + ' ' + remote.className + '}\x1b[0m');
			} else if (remote.value != null) {
				pieces.push(remote.value);
			} else {
				pieces.push(remote);
			}
		}

		console.log(...pieces);
	});

	loadHawkejs();

	await new Promise(function(resolve, reject) {
		server = http.createServer(function onReq(req, res) {

			var url = __Protoblast.Classes.RURL.parse(req.url),
			    renderer = hawkejs.createRenderer(),
			    templates;

			req.renderer = renderer;
			renderer.prepare(req, res);
			renderer.internal('url', url);

			// End stylesheet requests with a generic valid response
			if (url.pathname.indexOf('.css') > -1) {
				return res.end('body{color: #101010}');
			}

			if (url.pathname == '/hawkejs/hawkejs-client.js') {

				__Protoblast.getClientPath({
					modify_prototypes : true,
					ua                : req.headers.useragent,
					enable_coverage   : do_coverage,
				}).done(function gotClientFile(err, path) {

					if (err) {
						throw err;
					}

					fs.createReadStream(path).pipe(res);
				});

				return;
			}

			// Serve multiple template files
			if (url.pathname == '/hawkejs/templates') {

				var names = url.param('name');

				if (!names) {
					res.status = 500;
					return res.end('No template names have been given');
				}

				hawkejs.getFirstAvailableSource(names, function gotResult(err, result) {

					if (err) {
						res.status = 500;
						return res.end(String(err));
					}

					if (!result || !result.name) {
						res.status = 400;
						return res.end('Could not find any of the given templates');
					}

					res.setHeader('content-type', 'application/json;charset=utf-8');
					res.end(JSON.stringify(result));
				});

				return;
			}

			if (actions[url.pathname]) {
				return actions[url.pathname](req, res, renderer, responder);
			}

			templates = url.pathname.slice(1);

			renderer.renderHTML(templates).done(function afterRender(err, html) {

				if (err != null) {
					throw err;
				}

				responder(html);
			});

			function responder(body, type) {

				if (!type) {
					if (typeof body !== 'string') {

						// Stringify using json-dry
						body = __Protoblast.Bound.JSON.dry(body);

						// Tell the client to expect a json-dry response
						type = 'application/json-dry';
					} else {
						type = 'text/html';
					}
				}

				// Only send the mimetype if it hasn't been set yet
				if (res.getHeader('content-type') == null) {
					res.setHeader('content-type', type + ";charset=utf-8");
				}

				res.end(body);
			}

		}).listen(0, '0.0.0.0', function listening() {
			port = server.address().port;
			resolve();
		});
	});
}<|endoftext|>


<commit_before>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const processTree = require("../lib/process-tree");

let treeSpy = function(logTree) {
  let spy = { };

  spy.tree = logTree;

  spy.storeProcess = function(process) {
    spy.process = process;
  };

  spy.messages = [ ];
  spy.log = function(message) {
    spy.messages.push(message)
  };

  return spy;
};

let spy;
let spyOnTree = async function(done, setup) {
  spy = await processTree(treeSpy, setup)
  done();
};

describe("a processTree with no children", () => {
  beforeEach(done => {
    spyOnTree(done, o => {});
  });

  it("returns a spy", () => {
    expect(spy.tree).toBeDefined();
  });

  it("logs two messages once finished running", done => {
    spy.process.then(value => {
      expect(spy.messages.length).toBe(2);

      done();
    });
  });

  it("has no description", () => {
    expect(spy.tree.d || "").toBe("");
  });
});

describe("a lone processTree with some setup time", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.run = () => new Promise((resolve, reject) => {
        setTimeout(() => {resolve();}, 50);
      });
    });
  });

  it("doesn't log both messages right away", () => {
    expect(spy.messages.length).toBeLessThan(2);
  });

  it("logs both messages in the end", done => {
    spy.process.then(value => {
      expect(spy.messages.length).toBe(2);

      done();
    });
  });
});

describe("a processTree with one child and some delays", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.add(() => {});

      o.runBefore = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run before");
          resolve();
        }, 10);
      });

      o.run = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run");
          resolve();
        }, 10);
      });

      o.runAfter = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run after");
          resolve();
        }, 10);
      });
    });
  });

  describe("the resulting log", () => {
    beforeEach(done => {
      spy.process.then(value => {done();});
    });

    it("has 7 messages", () => {
      expect(spy.messages.length).toBe(7);
    });

    it("starts with a 'begin' message", () => {
      expect(spy.messages[0][1]).toBe("begin");
    });

    it("runs runBefore() first", () => {
      expect(spy.messages[1][2]).toBe("run before");
    });

    it("runs run() after runBefore()", () => {
      expect(spy.messages[2][2]).toBe("run");
    });

    it("logs a second 'begin' after run()", () => {
      expect(spy.messages[3][1]).toBe("begin");
    });

    it("logs a 'done' right after the second 'begin'", () => {
      expect(spy.messages[4][1]).toBe("done");
    });

    it("runs runAfter() after children are done", () => {
      expect(spy.messages[5][2]).toBe("run after");
    });

    it("finishes with a final 'done'", () => {
      expect(spy.messages[6][1]).toBe("done");
    });
  });
});

describe("a binary processTree with four grandchildren", () => {
  beforeEach(done => {
    let add_two_leaf_nodes = o => {
      o.add(() => {});
      o.add(() => {});
    };

    let add_two_parent_nodes = o => {
      o.add(add_two_leaf_nodes);
      o.add(add_two_leaf_nodes);
    };

    spyOnTree(done, add_two_parent_nodes);
  });

  describe("its logTree", () => {
    it("has two children", () => {
      expect(spy.tree.c.length).toBe(2);
    });

    it("has two grandchildren under its first child", () => {
      expect(spy.tree.c[0].c.length).toBe(2);
    });

    it("has two grandchildren under its second child", () => {
      expect(spy.tree.c[1].c.length).toBe(2);
    });
  });

  describe("the resulting log", () => {
    beforeEach(done => {
      spy.process.then(value => {done();});
    });

    it("has 14 messages", () => {
      expect(spy.messages.length).toBe(14);
    });

    describe("its first message", () => {
      it("has a 'begin' code", () => {
        expect(spy.messages[0][1]).toBe("begin");
      });

      it("has an empty message", () => {
        expect(spy.messages[0][2]).toBe("");
      });
    });

    describe("its second message", () => {
      it("has a 'begin' code", () => {
        expect(spy.messages[1][1]).toBe("begin");
      });

      it("has an address of [0]", () => {
        expect(spy.messages[1][2]).toBe(0);
      });
    });

    it("contains a begin [1] message", () => {
      let found_it = false;
      for (let msg of spy.messages)
        if (msg[1] === "begin" && msg.length === 4 && msg[2] === 1)
          found_it = true;

      expect(found_it).toBe(true);
    });

    it("contains a begin [1, 0] message", () => {
      let found_it = false;
      for (let msg of spy.messages)
        if (msg[1] === "begin" && msg.length === 5
            && msg[2] === 1 && msg[3] === 0)
          found_it = true;

      expect(found_it).toBe(true);
    });
  });
});

describe("a processTree with a description and no children", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.description = "the lone root";
    });
  });

  it("remembers its description", () => {
    expect(spy.tree.d).toBe("the lone root");
  });

  it("stores no children", () => {
    expect(spy.tree.c || []).toEqual([]);
  });
});

describe("a two-node processTree with descriptions", () => {
  beforeEach(done => {
    spyOnTree(done, root => {
      root.description = "the root";

      root.add(leaf => {
        leaf.description = "the leaf"
      });
    });
  });

  it("remembers its root description", () => {
    expect(spy.tree.d).toBe("the root");
  });

  it("stores one child", () => {
    expect(spy.tree.c.length).toBe(1);
  });

  it("remembers its leaf description", () => {
    expect(spy.tree.c[0].d).toBe("the leaf");
  });
});

describe("a tree with two failing nodes", () => {
  let error;

  beforeEach(done => {
    let addLeaf = (parentNode, id) => {
      parentNode.add(leaf => {
        leaf.description = "node " + id;
      });
    };

    error = undefined;

    Promise.resolve(processTree(treeSpy, root => {
      root.description = "the root";

      root.add(middle => {
        middle.description = "node 1";

        addLeaf(middle, "1a");
        addLeaf(middle, "1b");
        addLeaf(middle, "1c");
      });

      root.add(middle => {
        middle.description = "node 2";

        addLeaf(middle, "2a");

        middle.add(leaf => {
          leaf.description = "node 2b";

          throw "bad problem with node 2b";
        });

        addLeaf(middle, "2c");
      });

      root.add(middle => {
        middle.description = "node 3";

        addLeaf(middle, "3a");
        addLeaf(middle, "3b");
        addLeaf(middle, "3c");

        throw "bad problem with node 3";
      });

    })).then(v => {
      spy = v;
      done();

    }, e => {
      error = e;
      done();
    });
  });

  it("raises an error", () => {
    expect(error).toBeDefined();
  });

  describe("the exception object", () => {
    it("has an empty array of error messages", () => {
      expect(error.messages).toEqual([]);
    });

    it("has two child exceptions", () => {
      expect(error.children.length).toBe(2);
    });
  });
});
<commit_msg>:white_check_mark: Map out exception tree<commit_after>// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const processTree = require("../lib/process-tree");

let treeSpy = function(logTree) {
  let spy = { };

  spy.tree = logTree;

  spy.storeProcess = function(process) {
    spy.process = process;
  };

  spy.messages = [ ];
  spy.log = function(message) {
    spy.messages.push(message)
  };

  return spy;
};

let spy;
let spyOnTree = async function(done, setup) {
  spy = await processTree(treeSpy, setup)
  done();
};

describe("a processTree with no children", () => {
  beforeEach(done => {
    spyOnTree(done, o => {});
  });

  it("returns a spy", () => {
    expect(spy.tree).toBeDefined();
  });

  it("logs two messages once finished running", done => {
    spy.process.then(value => {
      expect(spy.messages.length).toBe(2);

      done();
    });
  });

  it("has no description", () => {
    expect(spy.tree.d || "").toBe("");
  });
});

describe("a lone processTree with some setup time", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.run = () => new Promise((resolve, reject) => {
        setTimeout(() => {resolve();}, 50);
      });
    });
  });

  it("doesn't log both messages right away", () => {
    expect(spy.messages.length).toBeLessThan(2);
  });

  it("logs both messages in the end", done => {
    spy.process.then(value => {
      expect(spy.messages.length).toBe(2);

      done();
    });
  });
});

describe("a processTree with one child and some delays", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.add(() => {});

      o.runBefore = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run before");
          resolve();
        }, 10);
      });

      o.run = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run");
          resolve();
        }, 10);
      });

      o.runAfter = () => new Promise(function(resolve, reject) {
        setTimeout(() => {
          o.log("info", "run after");
          resolve();
        }, 10);
      });
    });
  });

  describe("the resulting log", () => {
    beforeEach(done => {
      spy.process.then(value => {done();});
    });

    it("has 7 messages", () => {
      expect(spy.messages.length).toBe(7);
    });

    it("starts with a 'begin' message", () => {
      expect(spy.messages[0][1]).toBe("begin");
    });

    it("runs runBefore() first", () => {
      expect(spy.messages[1][2]).toBe("run before");
    });

    it("runs run() after runBefore()", () => {
      expect(spy.messages[2][2]).toBe("run");
    });

    it("logs a second 'begin' after run()", () => {
      expect(spy.messages[3][1]).toBe("begin");
    });

    it("logs a 'done' right after the second 'begin'", () => {
      expect(spy.messages[4][1]).toBe("done");
    });

    it("runs runAfter() after children are done", () => {
      expect(spy.messages[5][2]).toBe("run after");
    });

    it("finishes with a final 'done'", () => {
      expect(spy.messages[6][1]).toBe("done");
    });
  });
});

describe("a binary processTree with four grandchildren", () => {
  beforeEach(done => {
    let add_two_leaf_nodes = o => {
      o.add(() => {});
      o.add(() => {});
    };

    let add_two_parent_nodes = o => {
      o.add(add_two_leaf_nodes);
      o.add(add_two_leaf_nodes);
    };

    spyOnTree(done, add_two_parent_nodes);
  });

  describe("its logTree", () => {
    it("has two children", () => {
      expect(spy.tree.c.length).toBe(2);
    });

    it("has two grandchildren under its first child", () => {
      expect(spy.tree.c[0].c.length).toBe(2);
    });

    it("has two grandchildren under its second child", () => {
      expect(spy.tree.c[1].c.length).toBe(2);
    });
  });

  describe("the resulting log", () => {
    beforeEach(done => {
      spy.process.then(value => {done();});
    });

    it("has 14 messages", () => {
      expect(spy.messages.length).toBe(14);
    });

    describe("its first message", () => {
      it("has a 'begin' code", () => {
        expect(spy.messages[0][1]).toBe("begin");
      });

      it("has an empty message", () => {
        expect(spy.messages[0][2]).toBe("");
      });
    });

    describe("its second message", () => {
      it("has a 'begin' code", () => {
        expect(spy.messages[1][1]).toBe("begin");
      });

      it("has an address of [0]", () => {
        expect(spy.messages[1][2]).toBe(0);
      });
    });

    it("contains a begin [1] message", () => {
      let found_it = false;
      for (let msg of spy.messages)
        if (msg[1] === "begin" && msg.length === 4 && msg[2] === 1)
          found_it = true;

      expect(found_it).toBe(true);
    });

    it("contains a begin [1, 0] message", () => {
      let found_it = false;
      for (let msg of spy.messages)
        if (msg[1] === "begin" && msg.length === 5
            && msg[2] === 1 && msg[3] === 0)
          found_it = true;

      expect(found_it).toBe(true);
    });
  });
});

describe("a processTree with a description and no children", () => {
  beforeEach(done => {
    spyOnTree(done, o => {
      o.description = "the lone root";
    });
  });

  it("remembers its description", () => {
    expect(spy.tree.d).toBe("the lone root");
  });

  it("stores no children", () => {
    expect(spy.tree.c || []).toEqual([]);
  });
});

describe("a two-node processTree with descriptions", () => {
  beforeEach(done => {
    spyOnTree(done, root => {
      root.description = "the root";

      root.add(leaf => {
        leaf.description = "the leaf"
      });
    });
  });

  it("remembers its root description", () => {
    expect(spy.tree.d).toBe("the root");
  });

  it("stores one child", () => {
    expect(spy.tree.c.length).toBe(1);
  });

  it("remembers its leaf description", () => {
    expect(spy.tree.c[0].d).toBe("the leaf");
  });
});

describe("a tree with two failing nodes", () => {
  let error;

  beforeEach(done => {
    let addLeaf = (parentNode, id) => {
      parentNode.add(leaf => {
        leaf.description = "node " + id;
      });
    };

    error = undefined;

    Promise.resolve(processTree(treeSpy, root => {
      root.description = "the root";

      root.add(middle => {
        middle.description = "node 1";

        addLeaf(middle, "1a");
        addLeaf(middle, "1b");
        addLeaf(middle, "1c");
      });

      root.add(middle => {
        middle.description = "node 2";

        addLeaf(middle, "2a");

        middle.add(leaf => {
          leaf.description = "node 2b";

          throw "bad problem with node 2b";
        });

        addLeaf(middle, "2c");
      });

      root.add(middle => {
        middle.description = "node 3";

        addLeaf(middle, "3a");
        addLeaf(middle, "3b");
        addLeaf(middle, "3c");

        throw "bad problem with node 3";
      });

    })).then(v => {
      spy = v;
      done();

    }, e => {
      error = e;
      done();
    });
  });

  it("raises an error", () => {
    expect(error).toBeDefined();
  });

  describe("the exception object", () => {
    it("has an empty array of error messages", () => {
      expect(error.messages).toEqual([]);
    });

    it("has two child exceptions", () => {
      expect(error.children.length).toBe(2);
    });

    describe("its first child", () => {
      let first_child;
      beforeEach(() => {
        first_child = error.children[0];
      });

      it("has an empty array of error messages", () => {
        expect(first_child.messages).toEqual([]);
      });

      it("has one child exception", () => {
        expect(first_child.children.length).toBe(1);
      });

      it("has no grandchild exceptions", () => {
        expect(first_child.children[0].children).toEqual([]);
      });

      it("has the right message in its child", () => {
        expect(first_child.children[0].messages).toEqual(
          ["bad problem with node 2b"]);
      });
    });

    describe("its second child", () => {
      let second_child;
      beforeEach(() => {
        second_child = error.children[1];
      });

      it("has an empty array of child exceptions", () => {
        expect(second_child.children).toEqual([]);
      });

      it("has the right error message", () => {
        expect(second_child.messages).toEqual(
          ["bad problem with node 3"]);
      });
    });
  });
});
<|endoftext|>


<commit_before>require('../src/string-class.js');

describe('String Class Extension tests', () => {
  describe('Test hasVowels', () => {
    it('should return false if the string has no vowels', () => {
      expect('N VWLS'.hasVowels()).toBeFalsy();
      expect('n vwls'.hasVowels()).toBeFalsy();
      expect('@#$^&*%12345'.hasVowels()).toBeFalsy();
      expect(' '.hasVowels()).toBeFalsy();
    });

    it('should return true if the string has vowels', () => {
      expect('No vowels'.hasVowels()).toBeTruthy();
      expect('NO VOWELS'.hasVowels()).toBeTruthy();
      expect('n0 v0wels'.hasVowels()).toBeTruthy();
      expect('@#$^&*% 12345 e'.hasVowels()).toBeTruthy();
    });

    it('should return a boolean value', () => {
      expect(typeof ('1234'.hasVowels())).toBe('boolean');
    });

    it('should return a defined value', () => {
      expect(typeof ('1234'.hasVowels())).toBeDefined();
    });
  });

  describe('Test toUpper', () => {
    it('should return a string', () => {
      expect(typeof 'Lowercase'.toUpper()).toBe('string');
    });

    it('should return the string passed in uppercase', () => {
      expect('lowercase'.toUpper()).toEqual('LOWERCASE');
      expect('LowerCase'.toUpper()).toEqual('LOWERCASE');
      expect('L0werCAs3& letters'.toUpper()).toEqual('L0WERCAS3& LETTERS');
    });

    it('should verify that the inbuilt toUpper string method was not called', () => {
      spyOn(String.prototype, 'toUpperCase');

      // Trigger the toUpper method
      const spoof = 'JamesBond';
      spoof.toUpper();

      // Check whether the native javaScript toUpperCase was called
      expect(String.prototype.toUpperCase).not.toHaveBeenCalled();
    });
  });

  describe('Test toLower', () => {
    it('should return a string', () => {
      expect(typeof 'Lowercase'.toLower()).toBe('string');
    });

    it('should return the string passed in lowercase', () => {
      expect('LOWERCASE'.toLower()).toEqual('lowercase');
      expect('LowerCase'.toLower()).toEqual('lowercase');
      expect('L0werCAs3& letters'.toLower()).toEqual('l0wercas3& letters');
    });

    it('should verify that the inbuilt toUpper string method was not called', () => {
      spyOn(String.prototype, 'toLowerCase');
      const spoof = 'Ian Flemming';
      spoof.toLower();
      expect(String.prototype.toLowerCase).not.toHaveBeenCalled();
    });
  });

  describe('Test upperCaseFirst', () => {
    it('should return a string', () => {
      expect(typeof 'Uppercase'.ucFirst()).toBe('string');
    });

    it('should return the input string in Titlecase', () => {
      expect('UCFIRST'.ucFirst()).toEqual('UCFIRST');
      expect('upperCasefirst'.ucFirst()).toEqual('UpperCasefirst');
      expect('uppercase first'.ucFirst()).toEqual('Uppercase first');
    });
  });

  describe('Test isQuestion', () => {
    it('should return true if the string is a question', () => {
      expect('Is this a question?'.isQuestion()).toBeTruthy();
    });

    it('should return false if the string is not a question', () => {
      expect('This is not a question'.isQuestion()).toBeFalsy();
    });

    it('should return a defined value', () => {
      expect('Is this a question?'.isQuestion()).toBeDefined();
    });
  });

  describe('Test words', () => {
    it('should return a list of the words in the string, as an array', () => {
      expect('A rose by any other'.words()).toEqual(['A', 'rose', 'by', 'any', 'other']);
      expect('A:rose,by?any!other'.words()).toEqual(['A', 'rose', 'by', 'any', 'other']);
      expect('rose'.words()).toEqual(['rose']);
      expect('rose'.words()).toEqual(['rose']);
      expect(''.words()).toEqual(['']);
    });

    it('should verify that the result of the words method is an array object', () => {
      expect('A rose by any other name'.words()).toBeDefined();
      expect(typeof 'A rose by any other name'.words()).toBe('object');
      expect(Array.isArray('A rose by any other name'.words())).toBeTruthy();
    });
  });

  describe('Test wordCount', () => {
    it('should return the number of words in the string.', () => {
      expect('A rose by any other name'.wordCount()).toBeDefined();
      expect('A rose by any other name'.wordCount()).toEqual(6);
      expect(typeof 'A rose by any other name'.wordCount()).toBe('number');
    });
  });

  describe('Test toCurrency', () => {
    it('should return a string', () => {
      expect(typeof '11111.11'.toCurrency()).toBe('string');
      expect('11111.11'.toCurrency()).toBeDefined();
    });

    it('should return a currency representation of the string', () => {
      expect('11111.11'.toCurrency()).toEqual('11,111.11');
      expect('11111'.toCurrency()).toEqual('11,111.00');
      expect('21111111.11'.toCurrency()).toEqual('21,111,111.11');
    });
  });

  describe('Test fromCurrency', () => {
    it('should return a number', () => {
      expect(typeof '11,111.11'.fromCurrency()).toBe('number');
      expect('11,111.11'.fromCurrency()).toBeDefined();
    });

    it('should return a number representation of the currency string', () => {
      expect('11,111.11'.fromCurrency()).toEqual(11111.11);
      expect('11111'.fromCurrency()).toEqual(11111.00);
      expect('21111111.11'.fromCurrency()).toEqual(21111111.11);
    });
  });

  describe('Test isDigit', () => {
    it('should return true if the string passed is a digit', () => {
      expect('123456'.isDigit()).toBeTruthy();
    });

    it('should return false if the string passed is not a digit', () => {
      expect(' '.isDigit()).toBeFalsy();
      expect('This is not a number'.isDigit()).toBeFalsy();
      expect('*&^%'.isDigit()).toBeFalsy();
    });
  });
  describe('Test Even', () => {
    it('should return true if the string passed is an even digit', () => {
      expect('1234'.isEven()).toBeTruthy();
    });
    it('should return false if the string passed is an even digit', () => {
      expect('12345'.isEven()).toBeFalsy();
    });
  });
});
<commit_msg>Add toTitle and toCamel methods<commit_after>require('../src/string-class.js');

describe('String Class Extension tests', () => {
  describe('Test hasVowels', () => {
    it('should return false if the string has no vowels', () => {
      expect('N VWLS'.hasVowels()).toBeFalsy();
      expect('n vwls'.hasVowels()).toBeFalsy();
      expect('@#$^&*%12345'.hasVowels()).toBeFalsy();
      expect(' '.hasVowels()).toBeFalsy();
    });

    it('should return true if the string has vowels', () => {
      expect('No vowels'.hasVowels()).toBeTruthy();
      expect('NO VOWELS'.hasVowels()).toBeTruthy();
      expect('n0 v0wels'.hasVowels()).toBeTruthy();
      expect('@#$^&*% 12345 e'.hasVowels()).toBeTruthy();
    });

    it('should return a boolean value', () => {
      expect(typeof ('1234'.hasVowels())).toBe('boolean');
    });

    it('should return a defined value', () => {
      expect(typeof ('1234'.hasVowels())).toBeDefined();
    });
  });

  describe('Test toUpper', () => {
    it('should return a string', () => {
      expect(typeof 'Lowercase'.toUpper()).toBe('string');
    });

    it('should return the string passed in uppercase', () => {
      expect('lowercase'.toUpper()).toEqual('LOWERCASE');
      expect('LowerCase'.toUpper()).toEqual('LOWERCASE');
      expect('L0werCAs3& letters'.toUpper()).toEqual('L0WERCAS3& LETTERS');
    });

    it('should verify that the inbuilt toUpper string method was not called', () => {
      spyOn(String.prototype, 'toUpperCase');

      // Trigger the toUpper method
      const spoof = 'JamesBond';
      spoof.toUpper();

      // Check whether the native javaScript toUpperCase was called
      expect(String.prototype.toUpperCase).not.toHaveBeenCalled();
    });
  });

  describe('Test toLower', () => {
    it('should return a string', () => {
      expect(typeof 'Lowercase'.toLower()).toBe('string');
    });

    it('should return the string passed in lowercase', () => {
      expect('LOWERCASE'.toLower()).toEqual('lowercase');
      expect('LowerCase'.toLower()).toEqual('lowercase');
      expect('L0werCAs3& letters'.toLower()).toEqual('l0wercas3& letters');
    });

    it('should verify that the inbuilt toUpper string method was not called', () => {
      spyOn(String.prototype, 'toLowerCase');
      const spoof = 'Ian Flemming';
      spoof.toLower();
      expect(String.prototype.toLowerCase).not.toHaveBeenCalled();
    });
  });

  describe('Test upperCaseFirst', () => {
    it('should return a string', () => {
      expect(typeof 'Uppercase'.ucFirst()).toBe('string');
    });

    it('should return the input string in Titlecase', () => {
      expect('UCFIRST'.ucFirst()).toEqual('UCFIRST');
      expect('upperCasefirst'.ucFirst()).toEqual('UpperCasefirst');
      expect('uppercase first'.ucFirst()).toEqual('Uppercase first');
    });
  });

  describe('Test isQuestion', () => {
    it('should return true if the string is a question', () => {
      expect('Is this a question?'.isQuestion()).toBeTruthy();
    });

    it('should return false if the string is not a question', () => {
      expect('This is not a question'.isQuestion()).toBeFalsy();
    });

    it('should return a defined value', () => {
      expect('Is this a question?'.isQuestion()).toBeDefined();
    });
  });

  describe('Test words', () => {
    it('should return a list of the words in the string, as an array', () => {
      expect('A rose by any other'.words()).toEqual(['A', 'rose', 'by', 'any', 'other']);
      expect('A:rose,by?any!other'.words()).toEqual(['A', 'rose', 'by', 'any', 'other']);
      expect('rose'.words()).toEqual(['rose']);
      expect('rose'.words()).toEqual(['rose']);
      expect(''.words()).toEqual(['']);
    });

    it('should verify that the result of the words method is an array object', () => {
      expect('A rose by any other name'.words()).toBeDefined();
      expect(typeof 'A rose by any other name'.words()).toBe('object');
      expect(Array.isArray('A rose by any other name'.words())).toBeTruthy();
    });
  });

  describe('Test wordCount', () => {
    it('should return the number of words in the string.', () => {
      expect('A rose by any other name'.wordCount()).toBeDefined();
      expect('A rose by any other name'.wordCount()).toEqual(6);
      expect(typeof 'A rose by any other name'.wordCount()).toBe('number');
    });
  });

  describe('Test toCurrency', () => {
    it('should return a string', () => {
      expect(typeof '11111.11'.toCurrency()).toBe('string');
      expect('11111.11'.toCurrency()).toBeDefined();
    });

    it('should return a currency representation of the string', () => {
      expect('11111.11'.toCurrency()).toEqual('11,111.11');
      expect('11111'.toCurrency()).toEqual('11,111.00');
      expect('21111111.11'.toCurrency()).toEqual('21,111,111.11');
    });
  });

  describe('Test fromCurrency', () => {
    it('should return a number', () => {
      expect(typeof '11,111.11'.fromCurrency()).toBe('number');
      expect('11,111.11'.fromCurrency()).toBeDefined();
    });

    it('should return a number representation of the currency string', () => {
      expect('11,111.11'.fromCurrency()).toEqual(11111.11);
      expect('11111'.fromCurrency()).toEqual(11111.00);
      expect('21111111.11'.fromCurrency()).toEqual(21111111.11);
    });
  });

  describe('Test isDigit', () => {
    it('should return true if the string passed is a digit', () => {
      expect('123456'.isDigit()).toBeTruthy();
    });

    it('should return false if the string passed is not a digit', () => {
      expect(' '.isDigit()).toBeFalsy();
      expect('This is not a number'.isDigit()).toBeFalsy();
      expect('*&^%'.isDigit()).toBeFalsy();
    });
  });
  describe('Test Even', () => {
    it('should return true if the string passed is an even digit', () => {
      expect('1234'.isEven()).toBeTruthy();
    });
    it('should return false if the string passed is an even digit', () => {
      expect('12345'.isEven()).toBeFalsy();
    });
  });

  describe('Test TitleCase', () => {
    // Ignore rule for not titlecasing prepositions, conjunctions and articles
    it('should return the string input in TitleCase', () => {
      expect('I am to be titlecased'.toTitle()).toBeDefined();
      expect('I want to be titlecase'.toTitle()).toEqual('I Want To Be Titlecase');
      expect('can I be title and lowercase?'.toTitle()).toEqual('Can I Be Title And Lowercase?');
      expect('The rain falls over the plains'.toTitle()).toEqual('The Rain Falls Over The Plains');
    });
  });

  describe('Test CamelCase', () => {
    // All words including the first should be camelcased
    it('should return the string input in UpperCamelCase', () => {
      expect('I am to be camelcased'.toCamel()).toBeDefined();
      expect('I want to be camelcase'.toCamel()).toEqual('iWantToBeCamelcase');
      expect('can I be camel and lowercase?'.toCamel()).toEqual('canIBeCamelAndLowercase?');
      expect('The rain falls over the plains'.toCamel()).toEqual('theRainFallsOverThePlains');
    });
  });
});
<|endoftext|>