Skip to content

Commit

Permalink
Merge pull request #139 from wordpress-mobile/try/run-rn-app-tests-fr…
Browse files Browse the repository at this point in the history
…om-inside-gb

Ability to run the app and tests from inside Gutenberg
  • Loading branch information
hypest authored Sep 13, 2018
2 parents b2fb693 + 53cbb44 commit aec516b
Show file tree
Hide file tree
Showing 9 changed files with 251 additions and 16 deletions.
7 changes: 7 additions & 0 deletions extra-node-modules.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/** @format */
const enm = require( 'node-libs-react-native' );
enm.fs = __dirname + '/__mocks__/nodejsMock.js';
enm.net = __dirname + '/__mocks__/nodejsMock.js';
enm.canvas = __dirname + '/__mocks__/nodejsMock.js';

module.exports = enm;
5 changes: 3 additions & 2 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
verbose: true,
preset: 'jest-react-native',
testEnvironment: 'jsdom',
testPathIgnorePatterns: [ '/node_modules/', '/gutenberg/' ],
testPathIgnorePatterns: [ '/node_modules/', '/gutenberg/test/', '/gutenberg/packages/' ],
moduleFileExtensions: [
'native.js',
'android.js',
Expand All @@ -32,7 +32,8 @@ module.exports = {
'node',
],
moduleNameMapper: {
'@wordpress\\/(block-serialization-default-parser|blocks|data|element|deprecated|editor|redux-routine|block-library|components|keycodes|url|a11y|viewport|core-data|api-fetch|nux)$': '<rootDir>/gutenberg/packages/$1/src/index',
'@wordpress\\/(block-serialization-default-parser|blocks|data|element|deprecated|editor|redux-routine|block-library|components|keycodes|url|a11y|viewport|core-data|api-fetch|nux)$':
'<rootDir>/gutenberg/packages/$1/src/index',

// Mock the CSS modules. See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
'\\.(scss)$': '<rootDir>/__mocks__/styleMock.js',
Expand Down
15 changes: 15 additions & 0 deletions jest_gb.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/** @flow
* @format */

const main = require( './jest.config.js' );

module.exports = {
...main,
moduleNameMapper: {
'@wordpress\\/(blocks|data|element|deprecated|editor|redux-routine|block-library|components|keycodes|url|a11y|viewport|core-data|api-fetch|nux|block-serialization-default-parser)$':
'<rootDir>/../packages/$1/build/index',

// Mock the CSS modules. See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
'\\.(scss)$': '<rootDir>/__mocks__/styleMock.js',
},
};
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,19 @@
"sprintf-js": "^1.1.1"
},
"scripts": {
"check-gb-unused-babelrc": "cd gutenberg/; git ls-files --error-unmatch .babelrc 2>/dev/null; tracked=$?; cd ..; (if [ \"$tracked\" -gt 0 ]; then (exit 0); else (echo \"'.babelrc' is tracked in Gutenberg, cannot overwrite!\"; exit 1); fi)",
"bypass-gb-babel": "echo '{}' > gutenberg/.babelrc",
"test:bypass-gb-babel": "echo '{\"presets\": [\"@wordpress/default\"]}' > gutenberg/.babelrc",
"pre-build": "yarn check-gb-unused-babelrc && yarn bypass-gb-babel",
"test:pre-build": "yarn check-gb-unused-babelrc && yarn test:bypass-gb-babel",
"start": "yarn pre-build && yarn react-native start",
"start": "yarn react-native start",
"start:inside-gb": "yarn react-native start --config `pwd`/rn-cli-inside-gb.config.js",
"start:reset": "yarn clean:runtime && yarn start --reset-cache",
"start:debug": "yarn pre-build && node --inspect-brk node_modules/.bin/react-native start",
"start:inside-gb:reset": "yarn clean:runtime && yarn start:inside-gb --reset-cache",
"start:debug": "node --inspect-brk node_modules/.bin/react-native start",
"start:inside-gb:debug": "node --inspect-brk node_modules/.bin/react-native start:inside-gb",
"android": "react-native run-android",
"preios": "yarn preios:carthage",
"preios:carthage": "pushd react-native-aztec && (yarn install-aztec-ios; popd)",
"ios": "react-native run-ios",
"test": "yarn test:pre-build && cross-env NODE_ENV=test node node_modules/jest/bin/jest.js --verbose --config jest.config.js",
"test:debug": "yarn pre-build && cross-env NODE_ENV=test node --inspect-brk node_modules/jest/bin/jest.js --runInBand --verbose --config jest.config.js",
"test": "cross-env NODE_ENV=test node node_modules/jest/bin/jest.js --verbose --config jest.config.js",
"test:inside-gb": "cross-env NODE_ENV=test node node_modules/jest/bin/jest.js --verbose --config jest_gb.config.js",
"test:debug": "cross-env NODE_ENV=test node --inspect-brk node_modules/jest/bin/jest.js --runInBand --verbose --config jest.config.js",
"flow": "flow",
"prettier": "prettier-eslint --write $npm_package_config_jsfiles $npm_package_config_scssfiles",
"clean": "yarn clean:aztec; yarn cache clean; yarn clean:haste; yarn clean:jest; yarn clean:metro; yarn clean:react; yarn clean:watchman; yarn clean:node;",
Expand All @@ -63,6 +62,7 @@
"clean:haste": "rm -rf /tmp/haste-map-react-native-packager-*",
"clean:install": "yarn clean; yarn",
"clean:jest": "yarn jest --clearCache --config jest.config.js; rm -rf $TMPDIR/jest_*",
"clean:jest-inside-gb": "yarn jest --clearCache --config jest_gb.config.js; rm -rf $TMPDIR/jest_*",
"clean:metro": "rm -rf $TMPDIR/metro-cache-*;",
"clean:react": "rm -rf $TMPDIR/react-*",
"clean:node": "rm -rf node_modules",
Expand Down
42 changes: 42 additions & 0 deletions rn-cli-inside-gb.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/** @format */
const blacklist = require( 'metro' ).createBlacklist;
const path = require( 'path' );

const enm = require( './extra-node-modules.config.js' );

const { lstatSync, readdirSync } = require( 'fs' );
const getDirectoryNames = ( dir ) =>
readdirSync( dir ).filter( ( name ) => lstatSync( path.resolve( dir, name ) ).isDirectory() );

const wppackagenames = getDirectoryNames( path.resolve( __dirname, '../packages/' ) );

const mapper = function( accu, v ) {
accu[ '@wordpress/' + v ] = path.resolve( __dirname, '../packages/' + v );
return accu;
};

const wppackages = wppackagenames.reduce( mapper, {} );

module.exports = {
extraNodeModules: Object.assign( enm, wppackages ),
getProjectRoots() {
const roots = [ __dirname, path.resolve( __dirname, '../node_modules' ) ].concat(
Object.values( wppackages )
);
return roots;
},
getBlacklistRE: function() {
// Blacklist the nested GB filetree so modules are not resolved in duplicates,
// both in the nested directory and the parent directory.
return blacklist( [ new RegExp( path.basename( __dirname ) + '/gutenberg/.*' ) ] );
},
getTransformModulePath() {
return require.resolve( './sass-transformer-inside-gb.js' );
},
getSourceExts() {
return [ 'js', 'json', 'scss', 'sass' ];
},
getProvidesModuleNodeModules() {
return [ 'react-native-svg', 'react-native' ];
},
};
6 changes: 1 addition & 5 deletions rn-cli.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
/** @format */
const blacklist = require( 'metro' ).createBlacklist;

const enm = require( 'node-libs-react-native' );
enm.fs = __dirname + '/__mocks__/nodejsMock.js';
enm.net = __dirname + '/__mocks__/nodejsMock.js';
enm.canvas = __dirname + '/__mocks__/nodejsMock.js';
const enm = require( './extra-node-modules.config.js' );

module.exports = {
extraNodeModules: enm,
Expand Down
154 changes: 154 additions & 0 deletions sass-transformer-inside-gb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/** @format */

/**
* Parts of this source were derived and modified from react-native-sass-transformer,
* released under the MIT license.
*
* https://github.com/kristerkari/react-native-sass-transformer
*
* The MIT License (MIT)
* Copyright (c) 2018 Krister Kari
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

// TODO: create a new npm package with this transformer, or extend 'react-native-sass-transformer'

const fs = require( 'fs' );

const sass = require( 'node-sass' );
const semver = require( 'semver' );
const css2rn = require( 'css-to-react-native-transform' ).default;
const path = require( 'path' );

let upstreamTransformer = null;

const reactNativeVersionString = require( 'react-native/package.json' ).version;
const reactNativeMinorVersion = semver( reactNativeVersionString ).minor;

if ( reactNativeMinorVersion >= 52 ) {
upstreamTransformer = require( 'metro/src/transformer' );
} else if ( reactNativeMinorVersion >= 47 ) {
upstreamTransformer = require( 'metro-bundler/src/transformer' );
} else if ( reactNativeMinorVersion === 46 ) {
upstreamTransformer = require( 'metro-bundler/build/transformer' );
} else {
// handle RN <= 0.45
const oldUpstreamTransformer = require( 'react-native/packager/transformer' );
upstreamTransformer = {
transform( { src, filename, options } ) {
return oldUpstreamTransformer.transform( src, filename, options );
},
};
}

// TODO: need to find a way to pass the include paths and the default asset files via some config
const autoImportIncludePaths = [
path.join( path.dirname( __filename ), '../edit-post/assets/stylesheets' ),
];
const autoImportAssets = [
'_colors.scss',
'_breakpoints.scss',
'_variables.scss',
'_mixins.scss',
'_animations.scss',
'_z-index.scss',
];
const imports = '@import "' + autoImportAssets.join( '";\n@import "' ) + '";\n\n';

// Iterate through the include paths and extensions to find the file variant
function findVariant( name, extensions, includePaths ) {
for ( let i = 0; i < includePaths.length; i++ ) {
const includePath = includePaths[ i ];

// try to find the file iterating through the extensions, in order.
const foundExtention = extensions.find( ( extension ) => {
const fname = includePath + '/' + name + extension;
return fs.existsSync( fname );
} );

if ( foundExtention ) {
return includePath + '/' + name + foundExtention;
}
}

return false;
}

// Transform function taken from react-native-sass-transformer but extended to have more include paths
// and detect and use RN platform specific file variants
function transform( src, filename, options ) {
if ( typeof src === 'object' ) {
// handle RN >= 0.46
( { src, filename, options } = src );
}

const exts = [
// add the platform specific extension, first in the array to take precedence
options.platform === 'android' ? '.android.scss' : '.ios.scss',
'.native.scss',
'.scss',
];

if ( filename.endsWith( '.scss' ) || filename.endsWith( '.sass' ) ) {
const result = sass.renderSync( {
data: src,
includePaths: [ path.dirname( filename ), ...autoImportIncludePaths ],
importer: function( url /*, prev, done */ ) {
// url is the path in import as is, which LibSass encountered.
// prev is the previously resolved path.
// done is an optional callback, either consume it or return value synchronously.
// this.options contains this options hash, this.callback contains the node-style callback

const urlPath = path.parse( url );
const importerOptions = this.options;
const incPaths = importerOptions.includePaths.slice( 0 ).split( ':' );
if ( urlPath.dir.length > 0 ) {
incPaths.unshift( path.resolve( path.dirname( filename ), urlPath.dir ) ); // add the file's dir to the search array
}
const f = findVariant( urlPath.name, exts, incPaths );

if ( f ) {
return { file: f };
}

return new Error( url + ' could not be resolved in ' + incPaths );
},
} );
const css = result.css.toString();
const cssObject = css2rn( css, { parseMediaQueries: true } );

return upstreamTransformer.transform( {
src: 'module.exports = ' + JSON.stringify( cssObject ),
filename,
options,
} );
}
return upstreamTransformer.transform( { src, filename, options } );
}

module.exports.transform = function( { src, filename, options } ) {
if ( filename.endsWith( '.scss' ) || filename.endsWith( '.sass' ) ) {
// "auto-import" the stylesheets the GB webpack config imports
src = imports + src;
return transform( { src, filename, options } );
}
return upstreamTransformer.transform( { src, filename, options } );
};
12 changes: 12 additions & 0 deletions src/app/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,16 @@ describe( 'App', () => {
}
} );
} );

it( 'Heading block test', () => {
renderer
.create( <App /> )
.root.findAllByType( BlockHolder )
.forEach( ( blockHolder ) => {
if ( 'core/heading' === blockHolder.props.name ) {
const aztec = blockHolder.findByType( 'RCTAztecView' );
expect( aztec.props.text.text ).toBe( '<h2>Welcome to Gutenberg</h2>' );
}
} );
} );
} );
8 changes: 8 additions & 0 deletions src/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ global.document = doc;
if ( ! global.window.Node ) {
global.window.Node = jsdomLevel1Core.dom.level1.core.Node;
}

if ( ! global.window.matchMedia ) {
global.window.matchMedia = () => ( {
matches: false,
addListener: () => {},
removeListener: () => {},
} );
}

0 comments on commit aec516b

Please sign in to comment.