I am trying to unit test the Angular 2 Component using Jasmine. My Component is as follows
import { Component } from '#angular/core';
import {Employee} from './Employee';
#Component({
selector: 'emp-data',
templateUrl: './app/app.html'
})
export class EmployeeComponent {
emp:Employee;
private name: string = 'John';
constructor() {
this.emp =new Employee();
}
getTax():number{
console.log('sal' + this.emp.salary + ' desig ' + this.emp.designation);
if(this.emp.designation=='Manager'){
this.emp.tax = this.emp.salary*0.3;
}
if(this.emp.designation=='Lead'){
this.emp.tax = this.emp.salary*0.25;
}
console.log("Tax " + this.emp.tax);
return this.emp.tax;
}
printMessage():string{
return `Hello ${this.name}`;
};
}
The Spec file is as follows
import {EmployeeComponent} from './appcomponent';
describe('EmployeeComponent',()=>{
beforeEach(()=>{
this.app = new EmployeeComponent();
});
it('should have name property', function() {
expect(this.app.name).toBe('Mahesh');
});
it('should say hello with name property', function() {
expect(this.app.printMessage()).toBe('Hello Mahesh');
});
});
The Tester.html file is as follows
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>Ng App Unit Tests</title>
<link rel="stylesheet" href="../node_modules/jasmine-core/lib/jasmine-core/jasmine.css">
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/jasmine-html.js"></script>
<script src="../node_modules/jasmine-core/lib/jasmine-core/boot.js"></script>
<script src="../node_modules/es6-shim/es6-shim.min.js"></script>
<script src="../node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="../node_modules/es6-shim/es6-shim.min.js"></script>
<script src="../node_modules/reflect-metadata/Reflect.js"></script>
<script src="../node_modules/zone.js/dist/zone.js"></script>
<script src="../node_modules/#angular/core/testing/testing.js"></script>
<script src="systemjs.config.js"></script>
<script src="../app/appcomponent.js"></script>
<script src="../app/component.spec.js"></script>
</head>
<body>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script>
System.config({
packages: {
'app': {defaultExtension: 'js'}
}
});
System.import('app/component.spec')
.then(window.onload)
.catch(console.error.bind(console));
</script>
</body>
</html>
The Package.json is as follows
{
"name": "ng2-component-testing",
"version": "1.0.0",
"scripts": {
"start": "concurrently \"tsc -w\" \"node server.js\"",
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"typings": "typings",
"postinstall": "typings install",
"testLite": "live-server --open=unit-tests.html",
"lite-server-test": "lite-server --config=liteserver-test-config.json",
"test": "tsc && concurrently \"npm run tsc:w\" \"npm run lite-server-test\" "
},
"license": "ISC",
"dependencies": {
"#angular/common": "2.0.0-rc.1",
"#angular/compiler": "2.0.0-rc.1",
"#angular/core": "2.0.0-rc.1",
"#angular/http": "2.0.0-rc.1",
"#angular/platform-browser": "2.0.0-rc.1",
"#angular/platform-browser-dynamic": "2.0.0-rc.1",
"#angular/router": "3.0.0-alpha.3",
"bootstrap": "^3.3.6",
"es6-shim": "^0.35.1",
"jasmine-core": "~2.4.1",
"koa": "^1.2.0",
"koa-static": "^2.0.0",
"livereload": "^0.4.1",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"systemjs": "^0.19.24",
"zone.js": "0.6.6"
},
"devDependencies": {
"concurrently": "^2.0.0",
"jasmine-core": "2.4.1",
"lite-server": "^2.1.0",
"node-gyp": "^3.3.1",
"typescript": "^1.8.7",
"typings": "^0.7.5"
}
}
When I run the test, the following result is displayed
The following error messages are displayed in Console of the browser
I have tries various solutions on Stackoverflow but not successful in it.
So can anybody help me on this?
Thanks in advance.
Related
When I'm trying to deploy my NextJS (with Styled Components) application on AWS Amplify I'm getting these errors:
Error occurred prerendering page "/404"
TypeError: Cannot read property 'useState' of null
And that's all!
My _document.tsx
import React from 'react';
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-expect-error
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheet.collectStyles(<App {...props} />),
enhanceComponent: (Component) => Component
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
)
};
} finally {
sheet.seal();
}
}
render() {
return (
<Html lang="pl">
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght#300;400;500;600;700&display=swap" rel="stylesheet" />
<meta name="viewport" content="width=device-width" />
<meta charSet="utf-8" />
</Head>
<body>
<main aria-live="polite" aria-atomic="true">
<Main />
</main>
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
My package.json
{
"name": "app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --coverage --passWithNoTests",
"lint": "eslint src --fix"
},
"dependencies": {
"#shared/ui": "*",
"next": "12.1.6",
"react": "18.1.0",
"react-dom": "18.1.0",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0",
"styled-components": "^5.3.5"
},
"devDependencies": {
"#types/node": "17.0.35",
"#types/react": "18.0.14",
"#types/react-dom": "18.0.5",
"#types/styled-components": "^5.1.25",
"babel-plugin-styled-components": "^2.0.7",
"eslint": "^8.16.0",
"next-transpile-modules": "^9.0.0",
"prettier": "^2.6.2",
"typescript": "4.7.2"
}
}
My babel configuration
{
"presets": ["next/babel"],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}
It seems like something with SC rendering, but I don't know how to fix that. Please help.
I have recently rewritten my angular application. The previous project worked fine and I've not changed my django or apache2 configuration as it should just slip in.
n.b. I have changed the django home.html to include "-es2015" in the appropriate file names.
I'm currently getting the below errors in the inspector
Resource interpreted as Stylesheet but transferred with MIME type application/javascript: "http://146.148.41.45/static/assets/js/frontendwikiconverter.js". 146.148.41.45/:33
GET https://p.typekit.net/p.css?s=1&k=oov2wcw&ht=tk&f=39203&a=2613646&app=typekit&e=css net::ERR_CONNECTION_REFUSED oov2wcw.css:1
Uncaught SyntaxError: Invalid or unexpected token styles.css:1
Uncaught SyntaxError: Unexpected token '<' 12-es5.js:2
ERROR Error: Uncaught (in promise): ChunkLoadError: Loading chunk 12 failed. main-es5.js:1
My app.module:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule, NO_ERRORS_SCHEMA } from '#angular/core';
import { LocationStrategy, HashLocationStrategy } from '#angular/common';
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { PerfectScrollbarConfigInterface } from 'ngx-perfect-scrollbar';
import { ToastrModule } from 'ngx-toastr';
import { JwtTokenService } from './services/jwt-token.service'
import { IconModule, IconSetModule, IconSetService } from '#coreui/icons-angular';
import { LocalStorageService } from './services/local-storage-service.service';
import { NgxSmartModalModule } from 'ngx-smart-modal';
const DEFAULT_PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollX: true
};
import { AppComponent } from './app.component';
import { DefaultLayoutComponent } from './containers';
import { CommonModule } from "#angular/common";
import {AddToPlannerModule} from './views/planner/add-to-planner.module'
import { TooltipModule } from 'ngx-bootstrap/tooltip';
const APP_CONTAINERS = [
DefaultLayoutComponent
];
import {
AppAsideModule,
AppBreadcrumbModule,
AppHeaderModule,
AppFooterModule,
AppSidebarModule,
} from '#coreui/angular';
import { AppRoutingModule } from './app.routing';
import { BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { TabsModule } from 'ngx-bootstrap/tabs';
import { ChartsModule } from 'ng2-charts';
import { AuthorizeGuard } from './services/authorize-guard.service';
import { TokenInterceptor } from './services/http.interceptor'
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { DatePipe } from '#angular/common';
import { IsAdmin } from './services/can-activate-guard.service';
#NgModule({
imports: [
BrowserModule,
CommonModule,
TooltipModule.forRoot(),
BrowserAnimationsModule,
AppRoutingModule,
AppAsideModule,
AppBreadcrumbModule.forRoot(),
AppFooterModule,
AppHeaderModule,
AppSidebarModule,
PerfectScrollbarModule,
BsDropdownModule.forRoot(),
TabsModule.forRoot(),
ChartsModule,
IconModule,
IconSetModule.forRoot(),
HttpClientModule,
NgxSmartModalModule.forRoot(),
ToastrModule.forRoot({
positionClass :'toast-bottom-right'
}),
NgbModule,
AddToPlannerModule
],
declarations: [
AppComponent,
...APP_CONTAINERS,
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true,
deps: [JwtTokenService]
},
{
provide: LocationStrategy,
useClass: HashLocationStrategy
},
IconSetService,
JwtTokenService,
LocalStorageService,
AuthorizeGuard,
DatePipe,
IsAdmin
],
schemas: [
NO_ERRORS_SCHEMA
],
bootstrap: [
AppComponent
],
entryComponents: [],
exports: [
//AddToPlannerComponent
]
})
export class AppModule { }
Routing Module:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
// Import Containers
import { DefaultLayoutComponent } from './containers/default-layout/default-layout.component';
import { P404Component } from './views/site-admin/p404/p404.component';
import { P500Component } from './views/site-admin/p500/p500.component';
import { SignInComponent } from './views/useradmin/sign-in/sign-in.component';
import { JoinComponent } from './views/useradmin/join/join.component';
import { HomeComponent } from './views/general/home/home.component'
export const routes: Routes = [
{
path: '404',
component: P404Component,
data: {
title: 'Page 404'
}
},
{
path: '500',
component: P500Component,
data: {
title: 'Page 500'
}
},
{
path: 'signin',
component: SignInComponent,
data: {
title: 'Sign In'
}
},
{
path: 'join',
component: JoinComponent,
data: {
title: 'Join KeyStageWiki'
}
},
{
path: '',
redirectTo: 'home',
pathMatch: 'full'
},
{
path: '',
component: DefaultLayoutComponent,
data: {
title: 'KeyStageWiki'
},
children: [
{
path: 'home',
loadChildren: () => import('./views/general/home/home.module').then(m => m.HomeModule)
},
{
path: 'ad-manager',
loadChildren: () => import('./views/admin/ad-manager/ad-manager.module').then(m => m.AdManagerModule)
},
{
path: 'general',
loadChildren: () => import('./views/general/general.module').then(m => m.GeneralModule)
},
{
path: 'planner',
loadChildren: () => import('./views/planner/planner.module').then(m => m.PlannerModule)
},
{
path: 'user',
loadChildren: () => import('./views/useradmin/user-admin.module').then(m => m.UserAdminModule)
},
{
path: 'wiki',
loadChildren: () => import('./views/wiki/wiki.module').then(m => m.WikiModule)
},
{
path: 'lessons',
loadChildren: () => import('./views/lessons/lessons.module').then(m => m.LessonsModule)
},
]
},
{ path: '**', component: P404Component }
];
#NgModule({
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
exports: [RouterModule]
})
export class AppRoutingModule { }
home.html in the Django project:
{% load static %}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="{% static 'assets/img/keystagewiki.png' %}">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- <link rel="stylesheet" href="{% static 'ang/styles.css' %}"> -->
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="https://cdn.ckeditor.com/4.7.0/full-all/ckeditor.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://cdn.ckeditor.com/4.5.11/full-all/ckeditor.js"></script>
<link rel="stylesheet" href="https://use.typekit.net/oov2wcw.css">
<link rel="stylesheet" href="{% static 'assets/css/indigo-pink.css' %}">
<link rel="stylesheet" href="{% static 'assets/css/angular-calendar.css' %}">
<link rel="stylesheet" href="{% static 'assets/js/frontendwikiconverter.js' %}">
<link href="../css/style.css" type="text/scss" rel="stylesheet">
<link rel="stylesheet" href="{% static 'assets/css/ksw.css' %}">
</head>
<body style="max-width:1250px;margin:auto;" >
<app-root>
<img src="https://media.giphy.com/media/MDrmyLuEV8XFOe7lU6/giphy.gif" alt="Loading..." style="position:fixed; top:50%; left:50%; transform: translate(-50%, -50%);">
</app-root>
<script type="text/javascript" src="{% static 'ang/runtime.js' %}" defer></script>
<script type="text/javascript" src="{% static 'ang/polyfills.js' %}" defer></script>
<script type="text/javascript" src="{% static 'ang/main.js' %}" defer></script>
<script type="text/javascript" src="{% static 'ang/vendor.js' %}" defer></script>
<script type="text/javascript" src="{% static 'ang/styles.css' %}" defer></script>
<script type="text/javascript" src="{% static 'ang/scripts.js' %}" defer></script>
</body>
</html>
I'm very stuck, search and tried everything listed online. No progress. Any advise?
I'm new to Vue, but have a project with a login page. I can run it fine, but I'm trying to retro-add unit-testing (I know, I'm doing this backwards). I'm using Mocha + Chai and vue test utils. when I try to shallowMount I get an error saying that it cannot read a property. Here is the full error text:
1) Login
Has login text:
TypeError: Cannot read property 'email' of undefined
at Proxy.render (webpack:///./src/views/user/Login.vue?./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/vue-loader/lib??vue-loader-options:65:34)
at VueComponent.Vue._render (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:3640:22)
at VueComponent.updateComponent (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4168:21)
at Watcher.get (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4582:25)
at new Watcher (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4569:45)
at mountComponent (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4175:3)
at VueComponent.Vue.$mount (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:8512:10)
at init (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:3232:13)
at createComponent (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:6053:9)
at createElm (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:6001:9)
at VueComponent.patch [as __patch__] (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:6611:7)
at VueComponent.Vue._update (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4039:19)
at VueComponent.updateComponent (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4168:10)
at Watcher.get (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4582:25)
at new Watcher (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4569:45)
at mountComponent (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:4175:3)
at VueComponent.Vue.$mount (webpack:///./node_modules/vue/dist/vue.runtime.esm.js?:8512:10)
at mount (webpack:///./node_modules/#vue/test-utils/dist/vue-test-utils.js?:13265:21)
at shallowMount (webpack:///./node_modules/#vue/test-utils/dist/vue-test-utils.js?:13278:10)
at Context.eval (webpack:///./tests/unit/login.spec.js?:17:87)
at processImmediate (internal/timers.js:439:21)
Here is my packages file:
{
"name": "client",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"test:unit": "vue-cli-service test:unit",
"test:e2e": "vue-cli-service test:e2e",
"test": "mochapack --webpack-config webpack.config.js --require tests/setup.js tests/**/*.spec.js"
},
"dependencies": {
"axios": "^0.19.2",
"core-js": "^3.6.4",
"vue": "^2.6.11",
"vue-axios": "^2.1.5",
"vue-router": "^3.1.5",
"vuelidate": "^0.7.5",
"vuetify": "^2.1.0",
"vuex": "^3.1.2"
},
"devDependencies": {
"#vue/cli-plugin-babel": "^4.2.0",
"#vue/cli-plugin-e2e-cypress": "^4.2.0",
"#vue/cli-plugin-router": "^4.2.0",
"#vue/cli-plugin-unit-mocha": "^4.2.0",
"#vue/cli-plugin-vuex": "^4.2.0",
"#vue/cli-service": "^4.2.0",
"#vue/test-utils": "^1.0.0-beta.31",
"chai": "^4.1.2",
"jsdom": "^16.1.0",
"jsdom-global": "^3.0.2",
"mocha": "^7.0.1",
"mochapack": "^1.1.13",
"node-sass": "^4.12.0",
"sass": "^1.19.0",
"sass-loader": "^8.0.2",
"vue-cli-plugin-vuetify": "^2.0.4",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.3.0"
}
}
Here is my component code:
<template>
<v-container fluid fill-height>
<v-layout align-center justify-center>
<v-flex xs12 sm8 md4>
<v-card class="elevation-12">
<v-toolbar color="primary" dark flat>
<v-toolbar-title>Login form</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-form #submit.prevent="login">
<v-text-field
autofocus
v-model="email"
label="Email"
prepend-icon="mdi-account-circle"
#blur="$v.email.$touch()"
/>
<div class="red--text text--lighten-1" v-if="$v.email.$error">
<div v-if="!$v.email.required">
<v-icon color="red">mdi-alert-circle-outline</v-icon>
Email is required
</div>
<div v-if="!$v.email.email">
<v-icon color="red">mdi-alert-circle-outline</v-icon>
Invalid email address.
</div>
</div>
<v-text-field
v-model="password"
:type="showPassword ? 'text' : 'password'"
label="Password"
prepend-icon="mdi-lock"
:append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
#click:append="showPassword = !showPassword"
#blur="$v.password.$touch()"
/>
<div
class="red--text text--lighten-1"
v-if="$v.password.$error && !$v.password.required"
>
<v-icon color="red">mdi-alert-circle-outline</v-icon>
Password is required
</div>
<v-btn
type="submit"
color="success"
name="button"
:disabled="$v.$invalid"
>
Login now
</v-btn>
<v-btn
text
small
color="primary"
:to="{ name: 'forgotPassword' }"
>
Forgot your password?
</v-btn>
<div v-if="error" class="red--text text--lighten-1">
<v-icon color="red">mdi-alert-circle-outline</v-icon>
{{ getLoginErrorMsg() }}
</div>
</v-form>
</v-card-text>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
import { required, email } from "vuelidate/lib/validators";
export default {
name: "Login",
data() {
return {
email: "",
password: "",
error: null,
showPassword: false
};
},
validations: {
email: {
required,
email
},
password: {
required
}
},
methods: {
login() {
console.log("Entering component login method");
this.$store
.dispatch("user/login", {
username: this.email,
password: this.password
})
.then(() => {
console.log(
'this.$store.getters["user/passwordChangeRequired"]' +
this.$store.getters["user/passwordChangeRequired"]
);
if (this.$store.getters["user/passwordChangeRequired"]) {
console.log("push to changePassword");
this.$router.push({ name: "changePassword" });
} else {
console.log("pushing to home");
this.$router.push({ name: "home" });
}
})
.catch(err => {
this.error = err.response;
});
},
getLoginErrorMsg() {
if (this.error.status == 401) {
return "Invalid username or password";
} else {
// return `Login failed: {this.error.statusText}`;
return "failed";
}
}
}
};
</script>
<style></style>
Here is the test file:
import { expect } from "chai";
import { mount, shallowMount } from "#vue/test-utils";
import Login from "../../src/views/user/Login.vue";
describe("Login", () => {
it("Has login text", () => {
// const wrapper = mount(Login);
const wrapper = shallowMount(Login);
// not getting here.
expect(2).to.equal(2);
});
});
Note: neither mount or shallowMount works. They both throw the same error.
Here is my webpack.config.js file:
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
mode: 'development',
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
// this will apply to both plain `.js` files
// AND `<script>` blocks in `.vue` files
{
test: /\.js$/,
loader: 'babel-loader'
},
// this will apply to both plain `.css` files
// AND `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
]
},
plugins: [
// make sure to include the plugin for the magic
new VueLoaderPlugin()
]
}
I've spent hours googling and I can't really find anything. So, I'm clearly doing something really stupid, because no one else seems to be having this issue. Please tell me why it is throwing this error and unable to shallowMount or mount this vue component.
It appears that my tests/unit/index.js was missing some things... I didn't have vuelidate in there and I believe that was the issue. I changed it to the following and it now works:
// index.js
import Vue from 'vue';
import Vuetify from 'vuetify';
import VueRouter from 'vue-router';
import Vuelidate from "vuelidate";
Vue.config.productionTip = false;
Vue.use(Vuetify);
Vue.use(VueRouter);
Vue.use(Vuelidate);
I have tried to work out why this test is failing but cannot determine the reason, because I cannot see what the sinon spy object is being called with.
Is there a better way to test sinon.calledWith so it will show the result and expected result?
In the test below the following check passes expect(onLoginClick.called).to.equal(true); but this does not expect(onLoginClick.calledWith(expected)).to.equal(true);.
Any ideas why?
How can I check myself by seeing the actual value onLoginClick is called with vs the expected?
I am running the tests via "npm run test", the project can be cloned and run from https://github.com/Rob-Leggett/react_redux_webpack
Thanks for any answers and time taken to assist with this question.
Test
import React from 'react';
import { mount, shallow } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import Login from '../app/components/login/Login';
describe('<Login/>', function () {
it('should click login button with credentials', () => {
// given
const expected = { username: 'test', password: 'user' };
const errors = [];
const onLoginClick = sinon.spy();
const wrapper = mount(<Login errors={errors} onLoginClick={onLoginClick} />);
// when
wrapper.ref('username').simulate('change', {target: {value: 'test'}});
wrapper.ref('password').simulate('change', {target: {value: 'user'}});
wrapper.find('button').simulate('click');
// then
//expect(onLoginClick.calledWith(expected)).to.equal(true);
expect(onLoginClick.called).to.equal(true);
});
});
Component
import React, { Component, PropTypes } from 'react'
export default class Login extends Component {
renderErrors() {
const { errors } = this.props;
return errors.map((error, i) => {
return (
<p key={i} style={{color:'red'}}>{error}</p>
);
});
}
render() {
return (
<div>
<input type='text' ref='username' className="form-control" style={{ marginRight: '5px' }} placeholder='Username'/>
<input type='password' ref='password' className="form-control" style={{ marginRight: '5px' }} placeholder='Password'/>
<button onClick={() => this.handleLogin()} className="btn btn-primary">
Login
</button>
{this.renderErrors()}
</div>
)
}
handleLogin() {
const { onLoginClick } = this.props;
const credentials = {
username: this.refs.username.value.trim(),
password: this.refs.password.value.trim()
};
onLoginClick(credentials)
}
}
Login.propTypes = {
onLoginClick: PropTypes.func.isRequired,
errors: PropTypes.arrayOf(PropTypes.string)
};
package.json
{
"name": "react_redux_webpack_client",
"version": "1.0.0",
"description": "A ReactJS Client",
"scripts": {
"test": "mocha test/helpers/browser.js test/**/*.spec.js",
"dev": "webpack-dev-server --content-base public/ --hot --inline",
"build": "webpack -p --display-error-details"
},
"repository": {
"type": "git",
"url": "https://github.com/Rob-Leggett/react_redux_webpack.git"
},
"author": "Robert Leggett",
"license": "MIT",
"homepage": "https://github.com/Rob-Leggett/react_redux_webpack",
"bugs": {
"url": "https://github.com/Rob-Leggett/react_redux_webpack/issues"
},
"devDependencies": {
"chai": "^3.5.0",
"css-loader": "^0.26.1",
"enzyme": "^2.7.1",
"extract-text-webpack-plugin": "^1.0.1",
"html-webpack-plugin": "^2.26.0",
"jsdom": "^9.9.1",
"mocha": "^3.2.0",
"node-sass": "^4.3.0",
"react-addons-test-utils": "^15.4.2",
"sass-loader": "^4.1.1",
"sinon": "^1.17.7",
"style-loader": "^0.13.1",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-register": "^6.22.0",
"body-parser": "^1.15.2",
"classnames": "^2.2.5",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.2",
"redux": "^3.6.0",
"redux-thunk": "^2.2.0",
"whatwg-fetch": "^2.0.1"
}
}
To find out more then true/false in your test, you can can get the args from the Sinon spy like this:
const spyCall = onLoginClick.getCall(0);
expect(spyCall.args[0]).to.equal(expected)
Now the failing test should show you the args you really got.
See http://sinonjs.org/docs/
Despite my best efforts, I can't seem to get my testRunner.html to acknowledge my tests when I run the testRunner.html page in the browser. I've confirmed that it pulls in the test files and runs through the expect but the test runner is still saying that zero passed and zero failed. I've also tried moving the mocha.run() command into the testRunner.html page as an inline script to no effect.
What have I configured incorrectly?
testRunner.html
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "utf-8" />
<title> Tests </title>
<link href = "../node_modules/mocha/mocha.css" rel = "stylesheet">
</head>
<body>
<div id="mocha"></div>
<script src="../node_modules/mocha/mocha.js"></script>
<script>
mocha.setup('bdd');
</script>
<script src = "../node_modules/requirejs/require.js" data-main = "test.config.js"></script>
</body>
</html>
test.config.js
require.config({
baseUrl: '../src/public/js',
paths: {
jquery: '//code.jquery.com/jquery-2.1.1.min',
chai: '/../../../node_modules/chai/chai',
underscore: '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.6.0/underscore-min',
backbone: '//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min',
marionette: 'http://marionettejs.com/downloads/backbone.marionette',
handlebars: '//cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars',
syphon: '//cdnjs.cloudflare.com/ajax/libs/backbone.syphon/0.4.1/backbone.syphon.min'
},
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
marionette: {
deps: ['backbone'],
exports: 'Marionette'
},
syphon: {
deps: ['backbone', 'marionette'],
exports: 'Backbone.Syphon'
},
handlebars: {
exports: 'Handlebars'
}
}
});
require([
'../../../test/src/appTest'
], function() {
if (typeof mochaPhantomJS !== "undefined") {
mochaPhantomJS.run();
}
else {
mocha.run();
}
});
appTest.js
define(['chai'], function(chai) {
describe('array', function() {
chai.expect(1+1).to.equal(2);
});
});
You need to put your test in an it call:
define(['chai'], function(chai) {
describe('array', function() {
it("1 + 1 = 2", function () {
chai.expect(1+1).to.equal(2);
});
});
});
This is wholly an issue with how you are using Mocha. RequireJS is not a factor at all here.