288 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* global describe it expect beforeEach */
 | 
						|
const isArray = require('lodash/isArray');
 | 
						|
 | 
						|
const simpleAST = require('../__fixtures__/ast-simple.json');
 | 
						|
const withEditableAST = require('../__fixtures__/ast-with-markers.json');
 | 
						|
const withSeedKeysAST = require('../__fixtures__/ast-seed-keys.json');
 | 
						|
const withExtraLinesAST = require('../__fixtures__/ast-with-extra-lines.json');
 | 
						|
const orphanKeyAST = require('../__fixtures__/ast-orphan-key.json');
 | 
						|
const adjacentKeysAST = require('../__fixtures__/ast-adjacent-keys.json');
 | 
						|
const withBeforeAfterAST = require('../__fixtures__/ast-before-after.json');
 | 
						|
const emptyBeforeAST = require('../__fixtures__/ast-empty-before.json');
 | 
						|
const emptyAfterAST = require('../__fixtures__/ast-empty-after.json');
 | 
						|
const emptyCSSAST = require('../__fixtures__/ast-empty-css.json');
 | 
						|
const emptyHTMLAST = require('../__fixtures__/ast-empty-html.json');
 | 
						|
const doubleMarkerAST = require('../__fixtures__/ast-double-marker.json');
 | 
						|
const jsxSeedAST = require('../__fixtures__/ast-jsx-seed.json');
 | 
						|
const cCodeAST = require('../__fixtures__/ast-c-code.json');
 | 
						|
const explodedMarkerAST = require('../__fixtures__/ast-exploded-marker.json');
 | 
						|
const emptyContentAST = require('../__fixtures__/ast-empty-contents.json');
 | 
						|
 | 
						|
const addSeed = require('./add-seed');
 | 
						|
const { isObject } = require('lodash');
 | 
						|
 | 
						|
describe('add-seed plugin', () => {
 | 
						|
  const plugin = addSeed();
 | 
						|
  let file = { data: {} };
 | 
						|
 | 
						|
  beforeEach(() => {
 | 
						|
    file = { data: {} };
 | 
						|
  });
 | 
						|
 | 
						|
  it('returns a function', () => {
 | 
						|
    expect(typeof plugin).toEqual('function');
 | 
						|
  });
 | 
						|
 | 
						|
  it('adds a `files` property to `file.data`', () => {
 | 
						|
    plugin(simpleAST, file);
 | 
						|
    expect('files' in file.data).toBe(true);
 | 
						|
  });
 | 
						|
 | 
						|
  it('ensures that the `files` property is an object', () => {
 | 
						|
    plugin(simpleAST, file);
 | 
						|
    expect(isObject(file.data.files)).toBe(true);
 | 
						|
  });
 | 
						|
 | 
						|
  it('adds test objects to the files array following a schema', () => {
 | 
						|
    expect.assertions(17);
 | 
						|
    plugin(simpleAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const testObject = files.indexjs;
 | 
						|
    expect(Object.keys(testObject).length).toEqual(8);
 | 
						|
    expect(testObject).toHaveProperty('key');
 | 
						|
    expect(typeof testObject['key']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('ext');
 | 
						|
    expect(typeof testObject['ext']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('name');
 | 
						|
    expect(typeof testObject['name']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('contents');
 | 
						|
    expect(typeof testObject['contents']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('head');
 | 
						|
    expect(typeof testObject['head']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('tail');
 | 
						|
    expect(typeof testObject['tail']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('id');
 | 
						|
    expect(typeof testObject['id']).toBe('string');
 | 
						|
    expect(testObject).toHaveProperty('editableRegionBoundaries');
 | 
						|
    expect(isArray(testObject['editableRegionBoundaries'])).toBe(true);
 | 
						|
  });
 | 
						|
 | 
						|
  it('parses seeds without ids', () => {
 | 
						|
    expect.assertions(6);
 | 
						|
    plugin(simpleAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjs, indexhtml, indexcss } = files;
 | 
						|
 | 
						|
    expect(indexjs.contents).toBe(`var x = 'y';`);
 | 
						|
    expect(indexjs.key).toBe(`indexjs`);
 | 
						|
    expect(indexhtml.contents).toBe(`<html>
 | 
						|
  <body>
 | 
						|
  </body>
 | 
						|
</html>`);
 | 
						|
    expect(indexhtml.key).toBe(`indexhtml`);
 | 
						|
    expect(indexcss.contents).toBe(`body {
 | 
						|
  background: green;
 | 
						|
}`);
 | 
						|
    expect(indexcss.key).toBe(`indexcss`);
 | 
						|
  });
 | 
						|
 | 
						|
  it('removes region markers from contents', () => {
 | 
						|
    expect.assertions(2);
 | 
						|
    plugin(withEditableAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexcss } = files;
 | 
						|
 | 
						|
    expect(indexcss.contents).not.toMatch('--fcc-editable-region--');
 | 
						|
    expect(indexcss.editableRegionBoundaries).toEqual([1, 4]);
 | 
						|
  });
 | 
						|
 | 
						|
  // TODO: can we reuse 'name'? It's always 'index', I think, which suggests
 | 
						|
  // it could be reused as an id. Revisit this once the parser is live.
 | 
						|
  it('parses seeds with adjacent ids, adding the id to data', () => {
 | 
						|
    expect.assertions(3);
 | 
						|
    plugin(withSeedKeysAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexhtml, indexcss, indexjs } = files;
 | 
						|
 | 
						|
    expect(indexhtml.id).toBe('');
 | 
						|
    expect(indexcss.id).toBe('key-for-css');
 | 
						|
    expect(indexjs.id).toBe('key-for-js');
 | 
						|
  });
 | 
						|
 | 
						|
  it('throws if an id is anywhere except directly before a code node', () => {
 | 
						|
    expect.assertions(2);
 | 
						|
    expect(() => plugin(adjacentKeysAST, file)).toThrow(
 | 
						|
      '::id{#id}s must come before code blocks'
 | 
						|
    );
 | 
						|
    expect(() => plugin(orphanKeyAST, file)).toThrow(
 | 
						|
      '::id{#id}s must come before code blocks'
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('ignores empty lines between ::id{#id}s and code blocks', () => {
 | 
						|
    expect.assertions(1);
 | 
						|
    plugin(withSeedKeysAST, file);
 | 
						|
    const fileTwo = { data: {} };
 | 
						|
    plugin(withExtraLinesAST, fileTwo);
 | 
						|
    expect(file).toEqual(fileTwo);
 | 
						|
  });
 | 
						|
 | 
						|
  it('gets the before-user-code for each language', () => {
 | 
						|
    expect.assertions(3);
 | 
						|
    plugin(withBeforeAfterAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjs, indexhtml, indexcss } = files;
 | 
						|
 | 
						|
    expect(indexjs.head).toBe('');
 | 
						|
    expect(indexhtml.head).toBe(`<!-- comment -->`);
 | 
						|
    expect(indexcss.head).toBe(`body {
 | 
						|
  etc: ''
 | 
						|
}`);
 | 
						|
  });
 | 
						|
 | 
						|
  it('gets the after-user-code for each language', () => {
 | 
						|
    expect.assertions(3);
 | 
						|
    plugin(withBeforeAfterAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjs, indexhtml, indexcss } = files;
 | 
						|
 | 
						|
    expect(indexjs.tail).toBe(`function teardown(params) {
 | 
						|
  // after
 | 
						|
}`);
 | 
						|
    expect(indexhtml.tail).toBe('');
 | 
						|
    expect(indexcss.tail).toBe(`body {
 | 
						|
  background: blue;
 | 
						|
}`);
 | 
						|
  });
 | 
						|
 | 
						|
  it('throws an error if there is any code of an unsupported language', () => {
 | 
						|
    expect.assertions(1);
 | 
						|
    expect(() => plugin(cCodeAST, file)).toThrow(
 | 
						|
      "On line 30 'c' is not a supported language.\n" +
 | 
						|
        ' Please use one of js, css, html, jsx or py'
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('throws if there is before/after code with empty blocks', () => {
 | 
						|
    expect.assertions(2);
 | 
						|
    expect(() => plugin(emptyHTMLAST, file)).toThrow(
 | 
						|
      'Empty code block in --before-user-code-- section'
 | 
						|
    );
 | 
						|
    expect(() => plugin(emptyCSSAST, file)).toThrow(
 | 
						|
      'Empty code block in --after-user-code-- section'
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('quietly ignores empty before sections', () => {
 | 
						|
    expect.assertions(6);
 | 
						|
    plugin(emptyBeforeAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjs, indexhtml, indexcss } = files;
 | 
						|
 | 
						|
    expect(indexjs.head).toBe('');
 | 
						|
    expect(indexjs.tail).toBe('function teardown(params) {\n  // after\n}');
 | 
						|
    expect(indexhtml.head).toBe('');
 | 
						|
    expect(indexhtml.tail).toBe('');
 | 
						|
    expect(indexcss.head).toBe('');
 | 
						|
    expect(indexcss.tail).toBe('body {\n  background: blue;\n}');
 | 
						|
  });
 | 
						|
 | 
						|
  it('quietly ignores empty after sections', () => {
 | 
						|
    expect.assertions(6);
 | 
						|
    plugin(emptyAfterAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjs, indexhtml, indexcss } = files;
 | 
						|
 | 
						|
    expect(indexjs.head).toBe('');
 | 
						|
    expect(indexjs.tail).toBe('');
 | 
						|
    expect(indexhtml.head).toBe('<!-- comment -->');
 | 
						|
    expect(indexhtml.tail).toBe('');
 | 
						|
    expect(indexcss.head).toBe("body {\n  etc: ''\n}");
 | 
						|
    expect(indexcss.tail).toBe('');
 | 
						|
  });
 | 
						|
 | 
						|
  it('throws an error (with line number) if 2 markers appear on 1 line', () => {
 | 
						|
    expect.assertions(1);
 | 
						|
    expect(() => plugin(doubleMarkerAST, file)).toThrow(
 | 
						|
      `Line 8 has two markers. Each line should only have one.`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('throws if a javascript file has formatted a marker', () => {
 | 
						|
    expect.assertions(1);
 | 
						|
    expect(() => plugin(explodedMarkerAST, file)).toThrow(
 | 
						|
      `Line 66 has a malformed marker. It should be --fcc-editable-region--`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('handles jsx', () => {
 | 
						|
    expect.assertions(4);
 | 
						|
    plugin(jsxSeedAST, file);
 | 
						|
    const {
 | 
						|
      data: { files }
 | 
						|
    } = file;
 | 
						|
    const { indexjsx } = files;
 | 
						|
 | 
						|
    expect(indexjsx.head).toBe(`function setup() {}`);
 | 
						|
    expect(indexjsx.tail).toBe(`function teardown(params) {
 | 
						|
  // after
 | 
						|
}`);
 | 
						|
    expect(indexjsx.contents).toBe(`var x = 'y';
 | 
						|
 | 
						|
/* comment */
 | 
						|
const Button = () => {
 | 
						|
  return <button> {/* another comment! */} text </button>;
 | 
						|
};`);
 | 
						|
    expect(indexjsx.key).toBe(`indexjsx`);
 | 
						|
  });
 | 
						|
 | 
						|
  it('combines all the code of a specific language into a single file', () => {
 | 
						|
    /* Revisit this once we've decided what to do about multifile imports. I
 | 
						|
    think the best approach is likely to be use the following format for .files
 | 
						|
 | 
						|
    { css: [css files],
 | 
						|
      html: [html files],
 | 
						|
      ...
 | 
						|
    }
 | 
						|
 | 
						|
    or
 | 
						|
 | 
						|
     { css: {css files},
 | 
						|
      html: {html files},
 | 
						|
      ...
 | 
						|
    }
 | 
						|
 | 
						|
    depending on what's easier to work with in graphQL
 | 
						|
 | 
						|
    */
 | 
						|
  });
 | 
						|
 | 
						|
  it('should throw an error if a seed has no contents', () => {
 | 
						|
    expect.assertions(1);
 | 
						|
    expect(() => plugin(emptyContentAST, file)).toThrow(
 | 
						|
      `## --seed-contents-- must appear in # --seed-- sections`
 | 
						|
    );
 | 
						|
  });
 | 
						|
 | 
						|
  it('should have an output to match the snapshot', () => {
 | 
						|
    plugin(simpleAST, file);
 | 
						|
    expect(file.data).toMatchSnapshot();
 | 
						|
  });
 | 
						|
});
 |