Testing Angular 14 Standalone Components with Spectator - testing

Our test runner is Jest.
Our component is marked as standalone: true,
If try to set up spectator like this:
describe('OurComponent', () => {
let spectator: Spectator<OurComponent>;
const fakeActivatedRoute: ActivatedRoute = {
snapshot: {data: {}},
} as ActivatedRoute;
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
imports: [
// some imports
],
providers: [
// some providers
],
detectChanges: false,
shallow: true,
});
beforeEach(async () => {
spectator = componentFactory();
});
it('should be created', () => {
expect(spectator).toBeDefined();
});
});
Then we run into the following error:
"Error: Unexpected "OurComponent" found in the "declarations" array of the "TestBed.configureTestingModule" call, "OurComponent" is marked as standalone and can't be declared in any NgModule - did you intend to import it instead (by adding it to the "imports" array)?"
Using the Angular-CLI in order to generate resulted in a component with a test file which is built upon ComponentFixture.
How can we make it possible to test a standalone component using Spectator?

Depends on your spectator version (mine is 10.0.0) but you can use the declareComponent property :
const componentFactory: SpectatorFactory<OurComponent> = createComponentFactory({
component: OurComponent,
declareComponent: false,
});

Related

Watch package.json, add version to the bundle

I'm bundling a library with rollup and trying to add a version from package.json into the code itself.
Relevant bits of rollup config:
import pkg from './package.json'
output: [{
footer: `foo.version = '${pkg.version}'`
}]
The problem is, it's not getting updated with hotreload/watch. (rollup -w -c rollup.development.config.js')
Tried a few things:
using output plugins: they don't run again on watch
doing a dynamic import in the footer: not running again either
custom watcher plugin to include package.json: this triggers reload, but still not running the code that would read the updated value (plugins or footer)
Is there a way to do this? I wouldn't mind doing a full rebuild when package.json changes, but I'd like to avoid restarting the process manually. I'm frankly confused how such a simple thing can be this complicated.
Thanks
EDIT:
The version is not updated even when I do this:
const getVersion = () => ({
async renderStart () {
const data = await import('./package.json')
console.log('version: ' + data.version)
}
})
export default async () => ({
output: [{
plugins: [getVersion()]
}]
})
Thought it's a cache, so I tried invalidating it with ?date=' + Date.now(), but that just gives me Error: Cannot find module './package.json?test=1652969298057'. Seems like rollup is using require :(
Figured it out:
rollup.config.js
import glob from 'glob'
import path from 'path'
import fs from 'fs'
const watcher = (globs) => ({
buildStart () {
for (const item of globs) {
glob.sync(path.resolve(item)).forEach((filename) => { this.addWatchFile(filename) })
}
}
})
const updateVersion = () => ({
renderStart (outputOptions, inputOptions) {
outputOptions.footer = () => `library.version = ' + ${JSON.parse(fs.readFileSync('package.json', 'utf8')).version}'`
}
})
export default {
plugins: [
watcher(['package.json'])
],
output: [{
plugins: [
updateVersion()
]
}]
}

Effector: ".use argument should be a function" on attach

effector throws error ".use argument should be a function" at getCurrent (node_modules/effector/effector/region.ts:27:5) on attach method while testing.
I'm trying integration testing with mocking of some initial state.
//babel config
module.exports = (api) => {
if (api.env('test')) {
config.plugins.push([
'module-resolver',
{
root: ['.'],
alias: {
effector-react: 'effector-react/scope',
},
},
]);
}
return config;
};
//store.ts
export const getUsersFx = attach({
effect: getUsersOriginalFx,
source: [$clientId],
mapParams: (_, [clientId]) => ({
clientId
}),
});
//component.tsx
import { render } from '#testing-library/react';
import { Provider } from 'effector-react/scope'
describe('TestableComponent', () => {
test('should increment counter after click', () => {
const scope = fork()
const rendered = render(
<Provider value={scope}>
<TestableComponent />
</Provider>
);
})
})
I think the reason is that Effector mocks Effect and under the hood uses .use for effect callback mock. But then it change it to null or undefined and Effector throws error that fn in .use(fn) must be function
Effector mocks getUsersFx => getUsersFx.use(mockFn <- it's undefined i think).
Effector version: 22
Looks like the reason is multiple passes of effector/babel-plugin which you using for tests - error with attach is similiar:
https://github.com/effector/effector/issues/601
Multiple passes of babel-plugin will be supported in the next minor release of effector - for now you can check your babel configuration for duplicated usage of effector/babel-plugin

Dependency injection issue for `#ntegral/nestjs-sentry` package in nestjs app

I am have an issue with this package #ntegral/nestjs-sentry in nestjs. I have a custom logger I use in my application
#Injectable()
export class CustomLogger implements LoggerService {
constructor(#InjectSentry() private readonly client: SentryService) {}
log(message: any, ...optionalParams: any[]) {
this.client.instance().captureMessage(message, ...optionalParams);
}
}
I then inject the into User Controller and in the user.controller.spec.ts
describe('UsersController', () => {
let controller: UsersController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController],
providers: [
CustomLogger,
UsersService,
SentryService,
],
}).compile();
controller = module.get<UsersController>(UsersController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
I get this error
FAIL src/users/users.controller.spec.ts (9.449 s)
● UsersController › should be defined
Nest can't resolve dependencies of the CustomLogger (?). Please make sure that the argument Symbol(SentryToken) at index [0] is available in the RootTestModule context.
Potential solutions:
- If Symbol(SentryToken) is a provider, is it part of the current RootTestModule?
- If Symbol(SentryToken) is exported from a separate #Module, is that module imported within RootTestModule?
#Module({
imports: [ /* the Module containing Symbol(SentryToken) */ ]
})
I have tried adding the SentryService to the spec providers but that does not fix the error. Has anyone encountered this and how did you fix it.
I run in exactly the same issue. It seemed to be that the library uses a different token for its own Inject annotation. I was able to fix it in my tests by using the provided token for the SentryService mock.
import { SENTRY_TOKEN } from '#ntegral/nestjs-sentry';
// ...
const module: TestingModule = await Test.createTestingModule({
providers: [
// ...
{
provide: SENTRY_TOKEN,
useValue: { debug: jest.fn() }, // provide SentryService Mock here
},
],
})

Running Karma tests with VueJS single file component using Vueify

I am trying to run my unit tests with Karma. I have calendar.tests.js file that looks a lot like this:
import { handleSelectDay } from '../components/Calendar/index.vue'
describe('Calendar', () => {
describe('handleSelectDay', () => {
const data = {};
describe('updates data', () => {
it('should set the selectedDay to a new id', () => {
handleSelectDay('id');
expect(data.daySelected).to.equal('id');
});
});
});
});
When I run this test with Karma I get the following: TypeError: (0 , _index.handleSelectDay) is not a function is not a function
My karma.conf.js looks like:
module.exports = function (config) {
config.set({
frameworks: ['browserify', 'mocha'],
files: ['static/js/apps/FutureHours/test/calender.tests.js'],
preprocessors: {
'static/js/apps/**/test/*.js': ['browserify']
},
browsers: ['Chrome'],
logLevel: 'LOG_DEBUG',
plugins: [
'karma-mocha',
'karma-browserify',
'karma-chrome-launcher',
'karma-spec-reporter'
],
browserify: {
debug: true,
transform: [['babelify', { presets: ['env'] }], 'vueify']
}
})
}
How can I get Karma to play nice with VueJS single file components?
The problem with this is you can't have a named export from a .vue component. Instead, any methods used in the component will have to accessed via the component object in a unit test. Any functions used outside the component's methods, should probably live in their own ES module to make unit testing them much easier.

Jest - testing redux actions

I'm trying to test my app's redux actions using Jest. I've looked at the testing site # redux.js.org and other forums posts but I can't see why I'm getting the error I am, I think I'm not getting how the mocking works.
My action is in index.js:
export const setResponse = (res) => {
return {
type: 'RESPONSE_RECEIVED',
payload: res
}
};
My test is actions.test.js:
import * as actions from '../src/client/scripts/actions/index'
describe('actions', () => {
it('should create an action to receive a response', () => {
const payload = {response: 'solr_json'};
const expectedAction = {
type: 'RESPONSE_RECEIVED',
payload
}
expect(actions.setResponse(payload)).toEqual(expectedAction)
})
});
I got the error 'Expected undefined to equal Object...' soI thought actions.setResponse didn't exist, so I printed out actions.setResponse and it looks like this:
{ [Function: setResponse]
_isMockFunction: true,
getMockImplementation: [Function],
mock: { calls: [], instances: [] },
mockClear: [Function],
mockReturnValueOnce: [Function],
mockReturnValue: [Function],
mockImplementationOnce: [Function],
mockImpl: [Function],
mockImplementation: [Function],
mockReturnThis: [Function] }
So it seems the function is there, how do I actually call the function inside the Jest test? Even if I change
export const setResponse = (res) =>
to
export function setResponse(res)
(so it's the same format of the redux.js.org tutorial) I get the same error. For reference this is the jest part of my package.json:
"jest": {
"scriptPreprocessor": "node_modules/babel-jest",
"testFileExtensions": [
".test.js"
],
"testPathDirs": [
"__tests__"
],
"moduleFileExtensions": [
"js"
],
"unmockedModulePathPatterns": [
"node_modules/react",
"node_modules/react-addons-test-utils",
"node_modules/react-dom"
]
}
Thanks for any help
The problem seems that the module you want to test is mocked, cause you use unmockedModulePathPatterns. From the docs:
An array of regexp pattern strings that are matched against all
modules before the module loader will automatically return a mock for
them. If a module's path matches any of the patterns in this list, it
will not be automatically mocked by the module loader.
I would guess that if you remove this line the module is not automatically mocked. Normally its easier to mock the stuff that you want to mocked directly in your test using jest.mock. Or you add your source folder to the list of unmockedModulePathPatterns.