diff --git a/local-cli/util/__mocks__/fs.js b/local-cli/util/__mocks__/fs.js index f54060284..d559eb12e 100644 --- a/local-cli/util/__mocks__/fs.js +++ b/local-cli/util/__mocks__/fs.js @@ -11,9 +11,11 @@ 'use strict'; +const asyncify = require('async/asyncify'); const {EventEmitter} = require('events'); const {dirname} = require.requireActual('path'); const fs = jest.genMockFromModule('fs'); +const invariant = require('fbjs/lib/invariant'); const path = require('path'); const stream = require.requireActual('stream'); @@ -74,8 +76,7 @@ fs.readFile.mockImplementation(function(filepath, encoding, callback) { let node; try { node = getToNode(filepath); - // dir check - if (node && typeof node === 'object' && node.SYMLINK == null) { + if (isDirNode(node)) { callback(new Error('Error readFile a dir: ' + filepath)); } if (node == null) { @@ -90,13 +91,51 @@ fs.readFile.mockImplementation(function(filepath, encoding, callback) { fs.readFileSync.mockImplementation(function(filepath, encoding) { const node = getToNode(filepath); - // dir check - if (node && typeof node === 'object' && node.SYMLINK == null) { + if (isDirNode(node)) { throw new Error('Error readFileSync a dir: ' + filepath); } return node; }); +fs.writeFile.mockImplementation(asyncify(fs.writeFileSync)); + +fs.writeFileSync.mockImplementation((filePath, content, options) => { + if (options == null || typeof options === 'string') { + options = {encoding: options}; + } + invariant( + options.encoding == null || options.encoding === 'utf8', + '`options` argument supports only `null` or `"utf8"`', + ); + const dirPath = path.dirname(filePath); + const node = getToNode(dirPath); + if (!isDirNode(node)) { + throw fsError('ENOTDIR', 'not a directory: ' + dirPath); + } + node[path.basename(filePath)] = content; +}); + +fs.mkdir.mockImplementation(asyncify(fs.mkdirSync)); + +fs.mkdirSync.mockImplementation((dirPath, mode) => { + const parentPath = path.dirname(dirPath); + const node = getToNode(parentPath); + if (!isDirNode(node)) { + throw fsError('ENOTDIR', 'not a directory: ' + parentPath); + } + node[path.basename(dirPath)] = {}; +}); + +function fsError(code, message) { + const error = new Error(code + ': ' + message); + error.code = code; + return error; +} + +function isDirNode(node) { + return node && typeof node === 'object' && node.SYMLINK == null; +} + function readlinkSync(filepath) { const node = getToNode(filepath); if (node !== null && typeof node === 'object' && !!node.SYMLINK) { @@ -250,7 +289,7 @@ fs.close.mockImplementation((fd, callback = noop) => { callback(null); }); -let filesystem; +let filesystem = {}; fs.createReadStream.mockImplementation(filepath => { if (!filepath.startsWith('/')) { diff --git a/local-cli/util/__tests__/fs-mock-test.js b/local-cli/util/__tests__/fs-mock-test.js new file mode 100644 index 000000000..c4df35aa3 --- /dev/null +++ b/local-cli/util/__tests__/fs-mock-test.js @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @emails oncall+javascript_foundation + * @flow + * @format + */ + +'use strict'; + +/* eslint-disable no-unclear-flowtypes */ + +declare var jest: any; +declare var describe: any; +declare var it: any; + +jest.mock('fs'); + +const fs = require('fs'); + +describe('fs mock', () => { + describe('writeFileSync()', () => { + it('stores content correctly', () => { + fs.writeFileSync('/test', 'foobar', 'utf8'); + const content = fs.readFileSync('/test', 'utf8'); + expect(content).toEqual('foobar'); + }); + + it('fails on missing path', () => { + expect(() => + fs.writeFileSync('/dir/test', 'foobar', 'utf8'), + ).toThrowError('ENOENT: no such file or directory'); + }); + }); + + describe('mkdirSync()', () => { + it('creates folders that we can write files in', () => { + fs.mkdirSync('/dir', 0o777); + fs.writeFileSync('/dir/test', 'foobar', 'utf8'); + const content = fs.readFileSync('/dir/test', 'utf8'); + expect(content).toEqual('foobar'); + }); + }); +});