I am using Aurelia with Webpack. Based on the ESNext Skeleton Webpack.
https://github.com/aurelia/skeleton-navigation/tree/master/skeleton-esnext-webpack
I have some plain JS model classes like:
import {ValidationRules} from 'aurelia-validation';
export class Address {
street = '';
}
ValidationRules
.ensure('street').required()
.on(Address);
As soon as I run my Jasmine tests (via Karma) and also with Wallaby, I get the error:
'Message: Did you forget to add ".plugin('aurelia-validation)" to your main.js?'
OK - I've not got a main.js when running tests, so how to load the plugin?
I've tried doing something like this - using aurelia-testing:
import {StageComponent} from 'aurelia-testing';
import {bootstrap} from 'aurelia-bootstrapper-webpack';
...
let component;
beforeEach(done => {
component = StageComponent
.withResources();
component.bootstrap(aurelia => {
aurelia.use.plugin('aurelia-validation')
});
done();
});
But that does not work with Webpack - open issue with aurelia-bootstrapper-webpack. Or maybe I am doing it wrongly.
Is there some other way to load the validation plugin during the tests? Or get aurelia-testing working with webpack?
At the moment, I am completely blocked from doing any unit tests if I have the validation plugin, or attempt to use aurelia-testing.
I have it working using the aurelia-cli and wallaby. You were very close which I guess makes it even more frustrating. The secret for me is that the validation plugin had to be bootstrapped first with the beforeAll method in the spec file and then the system under test created in the beforeEach method. The following spec file worked for me and resolved the Message: Did you forget to add ".plugin('aurelia-validation') to your main.js" error.
import { SourceSystemEntity } from '../../../src/entities/sourceSystemEntity';
import { StageComponent } from 'aurelia-testing';
import { bootstrap } from 'aurelia-bootstrapper';
describe('SourceSystem class', () => {
let component;
let sut: SourceSystemEntity;
beforeAll(done => {
component = StageComponent.withResources().inView('<div></div>').boundTo({});
component.configure = (aurelia: Aurelia) => {
aurelia.use
.standardConfiguration()
.plugin('aurelia-validation');
};
component.create(bootstrap).then(() => {
done();
});
});
afterAll(() => {
component.dispose();
});
beforeEach(() => {
sut = new SourceSystemEntity();
});
it('has Validation enabled', () => {
expect(sut.hasValidation()).toBeTruthy();
});
});
From what I've found the ValidationRules are run during the import process. Since they haven't been put into the actual class. What worked for me was to put the ValidationRules into the constructor or another method and call them after the bootstrap has run. Still hasn't fixed the functionality of Validation during tests but it does let you run the unit tests
import {ValidationRules} from 'aurelia-validation';
export class Address {
street = '';
constructor() {
ValidationRules
.ensure('street').required()
.on(Address);
}
}
Related
I am working on a StencilJS project where I have to use MirageJS to make fake API data.
How to call server before StencilJS application loads.
In react we can call makeServer() in the index.ts file, but in the stencil, we don't have such a file.
How can we call this to start the mirage server, Please can someone suggest the correct way.
Below is my server.ts file
mirage/server.ts
import { createServer, Model } from 'miragejs';
import { auditFactory } from './factories';
import { processCollectionRequest } from './utils';
export const makeServer = async ({ environment = 'development' } = {}) => {
console.log('started server');
return createServer({
environment,
factories: {
people: auditFactory,
},
models: {
people: Model,
},
routes() {
this.namespace = '/api/v1';
this.get('/peoples', function (schema, request) {
let res = processCollectionRequest(schema, request, 'peoples', this);
// remove factory properties not in spec
res.items.forEach(e => ['associatedResourceId', 'associatedResourceName', 'associatedResourceType'].forEach(p => delete e[p]));
return res;
});
},
seeds(server) {
server.createList('audit', 20);
},
});
};
I'm not familiar with MirageJS so I might be off, but can you use globalScript (https://stenciljs.com/docs/config) and then run your Mirage server there?
I have a Vue 3 component that, when mounted in tests, cause warnings:
console.warn node_modules/#vue/runtime-core/dist/runtime-core.cjs.js:40
[Vue warn]: injection "Symbol(VueToastification)" not found.
at <ModifyJob ref="VTU_COMPONENT" >
at <VTUROOT>
I assume it's this one complaining https://github.com/Maronato/vue-toastification/blob/master/composition/index.js#L30.
I have nearly 100 of these warnings, so it's kind of hard to read test-run output. I've tried to mock provide for this dependency, but I can't seem to succeed:
let provide = {}
provide[VueToastification] = VueToastification
provide['VueToastification'] = VueToastification
provide[Symbol(VueToastification)] = VueToastification
provide[Symbol('VueToastification')] = VueToastification
provide['Symbol(VueToastification)'] = VueToastification
let options = {
global: {
provide: provide,
}
}
mount(ModifyJob, options)
Is this some Vue2/Vue3 incompatibility or do I just not understand the docs at https://vue-test-utils.vuejs.org/v2/api/#global-provide ? Can someone help me get rid of these warnings, ideally by allowing me to inject a mock so I can test that toasts are made?
That error actually indicates that the plugin isn't installed in the test Vue instance. You could make VueToastification available to the component under test through the global.plugins mounting option:
import { shallowMount } from '#vue/test-utils'
import MyComponent from '#/components/MyComponent.vue'
import VueToastificationPlugin from 'vue-toastification'
it('initializes', () => {
shallowMount(MyComponent, {
global: {
plugins: [VueToastificationPlugin]
}
})
})
Alternatively, if you want to verify that toast() (from VueToastification's useToast()) is called, you could mock vue-toastification:
import { shallowMount } from '#vue/test-utils'
import MyComponent from '#/components/MyComponent.vue'
jest.mock('vue-toastification')
it('should call toast', () => {
const toast = jest.fn()
require('vue-toastification').useToast.mockReturnValueOnce(toast)
shallowMount(MyComponent).vm.showToast()
expect(toast).toHaveBeenCalled()
})
I solved setting a global list of plugins according to https://next.vue-test-utils.vuejs.org/api/#config-global:
// In a jest.setup.js file
import { config } from "#vue/test-utils";
import VueToastificationPlugin from "vue-toastification";
config.global.plugins = [VueToastificationPlugin];
// In your jest.config.js
module.exports = {
...
setupFilesAfterEnv: ["./jest.setup.js"],
};
I try to test my web services, hosted in my Next.js app and I have an error with not found Next.js configuration.
My web service are regular one, stored in the pages/api directory.
My API test fetches a constant ATTACKS_ENDPOINT thanks to this file:
/pages/api/tests/api.spec.js
import { ATTACKS_ENDPOINT } from "../config"
...
describe("endpoints", () => {
beforeAll(buildOptionsFetch)
it("should return all attacks for attacks endpoint", async () => {
const response = await fetch(API_URL + ATTACKS_ENDPOINT, headers)
config.js
import getConfig from "next/config"
const { publicRuntimeConfig } = getConfig()
export const API_URL = publicRuntimeConfig.API_URL
My next.config.js is present and is used properly by the app when started.
When the test is run, this error is thrown
TypeError: Cannot destructure property `publicRuntimeConfig` of 'undefined' or 'null'.
1 | import getConfig from "next/config"
2 |
> 3 | const { publicRuntimeConfig } = getConfig()
I looked for solutions and I found this issue which talks about _manually initialise__ next app.
How to do that, given that I don't test React component but API web service ?
I solved this problem by creating a jest.setup.js file and adding this line of code
First add jest.setup.js to jest.config.js file
// jest.config.js
module.exports = {
// Your config
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};
AND then
// jest.setup.js
jest.mock('next/config', () => () => ({
publicRuntimeConfig: {
YOUR_PUBLIC_VARIABLE: 'value-of-env' // Change this line and copy your env
}
}))
OR
// jest.setup.js
import { setConfig } from 'next/config'
import config from './next.config'
// Make sure you can use "publicRuntimeConfig" within tests.
setConfig(config)
The problem I faced with testing with Jest was that next was not being initialized as expected. My solution was to mock the next module... You can try this:
/** #jest-environment node */
jest.mock('next');
import next from 'next';
next.mockReturnValue({
prepare: () => Promise.resolve(),
getRequestHandler: () => (req, res) => res.status(200),
getConfig: () => ({
publicRuntimeConfig: {} /* This is where you import the mock values */
})
});
Read about manual mocks here: https://jestjs.io/docs/en/manual-mocks
In my case, I had to:
Create a jest.setup.js file and
setConfig({
...config,
publicRuntimeConfig: {
BASE_PATH: '/',
SOME_KEY: 'your_value',
},
serverRuntimeConfig: {
YOUR_KEY: 'your_value',
},
});
Then add this in your jest.config.js file:
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
I am writing my first test for a react-native project using react-native-router-flux and react-redux
My code is something like
jest.autoMockOff();
jest.setMock('react-native', {
NativeModules: {}
});
jest.setMock('react-native-router-flux', {
Actions: {}
});
const mockStore = require('../../mock/Store');
const actions = require('../myActions');
...
// Some tests that test if the right actions are dispatched.
The above works, However when I use ES6 import instead of require I have a problem.
If I replace
const actions = require('../myActions');
with
import * as actions from "../myActions"
I get the below error.
Runtime Error
- Error: Cannot find module 'ReactNative' from 'react-native.js'
at Resolver.resolveModule (node_modules/jest-cli/node_modules/jest-resolve/src/index.js:117:17)
at Object.<anonymous> (node_modules/react-native/Libraries/react-native/react-native.js:175:25)
at Object.<anonymous> (node_modules/react-native-router-flux/src/Scene.js:10:18)
While I can work with this, I am curious to understand the reason for failure,
Also note that I am just not able to transpile react-native-router-flux with es2015 presets in .bablerc file and I think I will have to live with that limitation (of not being able to transpile react-native-router-flux).
myActions.js looks like
import {Actions} from 'react-native-router-flux';
export function searchRequest() {
return {
type: "search_request"
}
}
export function searchRequestFailure(error) {
return {
type: "search_request_failure",
error: error.toString()
}
}
export function searchRequestSuccess(payload) {
return {
type: "search_request_success",
payload: payload
}
}
export function search(nameOrAddress) {
return dispatch => {
dispatch(searchRequest())
return fetch("http://localhost:8080/search", {
method: "GET"
}).then((response) => {
return response.json()
}).then((responseData) => {
dispatch(searchRequestSuccess(responseData))
Actions.list() //react-native-router-flux dependency
}).catch(error => {
dispatch(searchRequestFailure(error))
})
}
}
Using react-native 0.26 and jest 12.1.1
That is not the correct ES6 conversion.
const actions = require('../myActions'); // requires the defaultMember of the exported module and
//ES6 (ES2015) equivalent is
import actions from '../myActions';
https://developer.mozilla.org/en/docs/web/javascript/reference/statements/import
I have a webcomponent that creates a shadow DOM and adds some html to its shadowRoot.
class SomeThing extends HTMLElement {
attachedCallback () {
this.el = this.createShadowRoot();
this.render();
}
render () {
this.el.innerHTML = '<h1>Hello</h1>';
}
}
export default SomeThing;
And I am compiling it with the help of webpack and its babel-core and babel-preset-es2015 plugins.
Also I am using Karma and Jasmine to write my Unit Test. This is what it looks like.
describe('some-thing', function () {
var someElement;
beforeEach(function () {
someElement = document.createElement('some-thing');
});
it('created element should match string representation', function () {
var expectedEl = '<some-thing></some-thing>';
var wrapper = document.createElement('div');
wrapper.appendChild(someElement);
expect(wrapper.innerHTML).toBe(expectedEl);
});
it('created element should have shadow root', function () {
var wrapper = document.createElement('div');
wrapper.appendChild(someElement);
expect(wrapper.querySelector('some-thing').shadowRoot).not.toBeNull();
})
});
I want to see if there is something in the shadowRoot of my element, and want to write test cases for the HTML and events created inside the shadowRoot. But the second test is failing. It is not able to add shadowRoot to the some-element DOM.
If anyone can help me out, that would be helpful.
I am also uploading the full test working project on Github. You can access it via this link https://github.com/prateekjadhwani/unit-tests-for-shadow-dom-webcomponents
Thanks in advance
I had a similar problem testing a web component but in my case I am using lit-element from polymer/lit-element. Lit-element provides life cycle hooks, template rendering using lit-html library (documentation).
So this is my problem and how I solved. I noticed that the component was added and the class executed constructor and I had access to public methods using:
const element = document.querySelector('my-component-name')
element.METHOD();
element.VARIABLE
But it never reached the hook firstUpdated, so I thought the problem was the speed the test executes vs the speed component is created. So I used the promised provided by lit-element API (updateComplete):
Note: I use mocha/chai instead of Jasmine
class MyComponent extends LitElement {
render() {
return html`<h1>Hello</h1>`
}
}
customElements.define('my-component', TodoApp);
let element;
describe('main', () => {
beforeEach(() => {
element = document.createElement("my-component");
document.querySelector('body').appendChild(element);
});
describe('test', () => {
it('Checks that header tag was added to shadowRoot', (done) => {
(async () => {
const res = await element.updateComplete;
const header = element.shadowRoot.querySelector('h1');
assert.notEqual(header, null);
done();
})();
});
});
});
So, my advice is create a promise and resolve it when the render function is executed, use the promise to sync the creation of the component with tests.
I am using this repository to test concepts
https://github.com/correju/polymer-playground