Closed lionminhu closed 5 years ago
It's strange though; the wiki post from ARc seems to imply that importing the sagas and testing them should not pose any problem.
This is a problem with ARc, since it doesn't mock sagas
For clarification, refer to this comment (https://github.com/diegohaz/arc/pull/101#issuecomment-280082146).
Instead of mocking sagas, it might just be possible to mock the require.context
entirely.
From https://github.com/facebook/create-react-app/issues/517#issuecomment-243488178
This should be solvable by a custom
__mocks__
file for the index module that exports all of the modules OR creates a Proxy object for the index module that has getters during runtime.
I'll start looking into this possibility.
ARc 위키에서 import하기 쉬울거라는 얘기는 없지 않나? 그리고 애초에 위키에서 말하는 테스팅은 컴포넌트들을 mock한 상태일테니 그다음에는 require.context 문제 없이 쉽게 되겠지
그리고 애초에 위키에서 말하는 테스팅은 컴포넌트들을 mock한 상태일테니
The wiki post I linked to above was about sagas, not components. Specifically, it is about unit/integration-testing sagas. It doesn't explain how the sagas could be tested if they cannot even be imported.
ARc 위키에서 import하기 쉬울거라는 얘기는 없지 않나?
But yes, the wiki says nothing about "importing" the sagas, so it might just be that the tests and the sagas being tested are even in the same file.
Installing babel-plugin-transform-require-context
(docs) and running npm test
results in the following error instead:
FAIL src/store/MainPage/sagas.test.js
● Test suite failed to run
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
at invariant (node_modules/fbjs/lib/invariant.js:42:15)
at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:308:76)
at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:399:32)
at render (node_modules/react-dom/lib/ReactMount.js:420:23)
at Object.<anonymous> (src/index.js:24:22)
at Object.<anonymous> (src/store/MainPage/sagas.js:12:91)
at Object.<anonymous> (src/store/MainPage/sagas.test.js:2:14)
at handle (node_modules/worker-farm/lib/child/index.js:44:8)
at process.<anonymous> (node_modules/worker-farm/lib/child/index.js:51:3)
at process.emit (events.js:196:13)
at emit (internal/child_process.js:860:12)
at processTicksAndRejections (internal/process/task_queues.js:84:9)
babel-plugin-transform-require-context 같은 플러그인들 보니까 require.context 자체를 바꾼다고 되어있어서 좀 꺼려지던데 모든 require.context에 대한 콜을 그 플러그인에서 지정한 함수로 가게 바꾸는 형식이라고
Defining a mock require.context
for every file that uses require.context
such as src/store/middlewares.js
as below (according to this)
// This condition actually should detect if it's an Node environment
if (typeof require.context === 'undefined') {
const fs = require('fs');
const path = require('path');
require.context = (base = '.', scanSubDirectories = false, regularExpression = /\.js$/) => {
const files = {};
function readDirectory(directory) {
fs.readdirSync(directory).forEach((file) => {
const fullPath = path.resolve(directory, file);
if (fs.statSync(fullPath).isDirectory()) {
if (scanSubDirectories) readDirectory(fullPath);
return;
}
if (!regularExpression.test(fullPath)) return;
files[fullPath] = true;
});
}
readDirectory(path.resolve(__dirname, base));
function Module(file) {
return require(file);
}
Module.keys = () => Object.keys(files);
return Module;
};
}
results in the same error as above with npm test
:
FAIL src/store/MainPage/sagas.test.js
● Test suite failed to run
Invariant Violation: _registerComponent(...): Target container is not a DOM element.
at invariant (node_modules/fbjs/lib/invariant.js:42:15)
at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:308:76)
at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:399:32)
at render (node_modules/react-dom/lib/ReactMount.js:420:23)
at Object.<anonymous> (src/index.js:24:22)
at Object.<anonymous> (src/store/MainPage/sagas.js:12:91)
at Object.<anonymous> (src/store/MainPage/sagas.test.js:2:14)
at handle (node_modules/worker-farm/lib/child/index.js:44:8)
at process.<anonymous> (node_modules/worker-farm/lib/child/index.js:51:3)
at process.emit (events.js:196:13)
at emit (internal/child_process.js:860:12)
at processTicksAndRejections (internal/process/task_queues.js:84:9)
And this nearly rules out the solution of mocking require.context
. Another solution is to mock the sagas as first mentioned, or to modify the codes such that require.context
is not used.
I'm more interested in the latter, as the former seems rather ARc-specific, and thus hard to search online.
Just to confirm, I've also tried using babel-plugin-require-context-hook
(according to this), but the same Invariant Violation
error showed up as above.
In src/store/sagas.js
(link), the usage of require.context
is as follows:
const req = require.context('.', true, /\.\/.+\/sagas\.js$/)
// ...
const sagas = []
req.keys().forEach((key) => {
sagas.push(req(key).default)
})
export default function* () {
yield sagas.map(fork)
}
Printing req.keys()
gives us a list of strings:
(7) ["./ArchivePage/sagas.js", "./MainPage/sagas.js", "./PostPage/sagas.js", "./SearchPage/sagas.js", "./SideBar/sagas.js", "./SignInPage/sagas.js", "./SignUpPage/sagas.js"]
0: "./ArchivePage/sagas.js"
1: "./MainPage/sagas.js"
2: "./PostPage/sagas.js"
3: "./SearchPage/sagas.js"
4: "./SideBar/sagas.js"
5: "./SignInPage/sagas.js"
6: "./SignUpPage/sagas.js"
length: 7
__proto__: Array(0)
The only thing we need is the list of directories of sagas files. We may be able to implement this without using require.context
.
I want to try out the solution that uses fs.readdirSync
(according to this Stack post), but even importing fs
from src/store/sagas.js
as import fs from 'fs'
results in the following error:
None of the following changed the result:
node: { fs: "empty" }
in the Webpack config (https://github.com/pugjs/pug-loader/issues/8#issuecomment-55568520)target: "async-node"
(https://github.com/pugjs/pug-loader/issues/8#issuecomment-360671614)I tried adding these by adding this near the end of the webpack.config.js
(right before module.exports = config
:
config = {
...config,
// node: {
// fs: 'empty',
// },
// target: "async-node",
}
The last comment was a mistake on my part; config
was already declared with const
, not with let
or var
.
Adding target: "async-node"
results in the following error:
Adding node: {fs: 'empty' }
makes the mentioned error message disappear.
However, when I added the following lines at the beginning of src/store/sagas.js
import fs from 'fs'
console.log(fs)
it outputs {}
, indicating that the imported fs
is an empty dictionary, probably because of node: {fs: 'empty' }
.
Adding the following to the webpack.config.js
(according to this post)
var fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
config = {
...config,
target: 'node',
externals: nodeModules,
}
results in the aforementioned error with Uncaught ReferenceError: require is not defined
.
Trying to dynamically import fs
by setting the externals
of config
from webpack.config.js
(according to this post)
config = {
...config,
externals: {
fs: 'require(\'fs\')',
},
}
results in the following error:
At this point, I'm starting to believe that it might be a better idea to manually provide an array of paths for sagas files for req.keys
(https://github.com/swpp201901-team06/swpp-project/issues/69#issuecomment-502202772). None of the solutions I've searched has solved this problem.
A better solution would be to study webpack and webpack configuration to figure out how require
statements within externals
attribute of module.exports
for webpack.config.js
works, but we're in a rush.
Even hardcoding is difficult, since I don't know how I would replace the default
attribute of req(key)
below:
req.keys().forEach((key) => {
sagas.push(req(key).default)
})
I've decided to give up on testing sagas. I'll have to modify ARc and study webpack to even hope for a clue, and our deadline is on Monday.
Mocking fs
might also be a possibility, but I'm not looking into that.
I'm currently trying to create tests for sagas for MainPage, but when I import any saga function into the test file:
running
npm test
results in an error:This is a problem with ARc, since it doesn't mock sagas (https://github.com/diegohaz/arc/issues/131#issuecomment-314497638).
I'm trying to figure out if there is a way to mock sagas for testing. As a reference, I'm following this guide to build tests for sagas.