I'm trying to use apollo (+ vue, django) but for some reason it won't get loaded/used in a component,this.$apollo is always undefined.
<script>
import { GET_ALL_USERS_QUERY } from '../js/graphql/queries/userQueries.js'
export default {
name: 'GraphQLTest',
data() {
return {
users: [],
loading: true
}
},
async mounted() {
this.loading = true
this.users = await this.$apollo.query({
query: GET_ALL_USERS_QUERY
})
this.loading = false
}
}
</script>
[Vue warn]: Error in mounted hook (Promise/async): "TypeError: Cannot read property 'query' of undefined"
main.js
import Vue from 'vue'
import { router } from './routes.js'
import store from './store.js'
import { createProvider } from './apollo.js'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
router,
store,
provide: createProvider(),
render: h => h(App),
}).$mount('#app')
apollo.js
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import { createApolloClient, restartWebsockets } from 'vue-cli-plugin-apollo/graphql-client'
// Install the vue plugin
Vue.use(VueApollo)
// Name of the localStorage item
const AUTH_TOKEN = 'jwt-token'
// Config
const defaultOptions = {
httpEndpoint: '/graphql',
wsEndpoint: null,
tokenName: AUTH_TOKEN,
persisting: false,
websocketsOnly: false,
ssr: false
}
// Call this in the Vue app file
export function createProvider (options = {}) {
// Create apollo client
const { apolloClient, wsClient } = createApolloClient({
...defaultOptions,
...options
})
apolloClient.wsClient = wsClient
// Create vue apollo provider
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$query: {
loadingKey: 'loading',
fetchPolicy: 'cache-and-network'
}
},
errorHandler (error) {
// eslint-disable-next-line no-console
console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
}
})
return apolloProvider
}
// Manually call this when user log in
export async function onLogin (apolloClient, token) {
localStorage.setItem(AUTH_TOKEN, token)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
}
}
// Manually call this when user log out
export async function onLogout (apolloClient) {
localStorage.removeItem(AUTH_TOKEN)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try {
await apolloClient.resetStore()
} catch (e) {
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
}
}
Why is apollo never loaded? something missing in the config?
[edit: same thing happens when following the tutorial : ]
import Vue from "vue"
import App from "./App.vue"
import { router } from './routes.js'
import ApolloClient from "apollo-boost"
import VueApollo from "vue-apollo"
const apolloProvider = new VueApollo({
defaultClient: new ApolloClient({
uri: "http://localhost:8000/graphql/"
})
})
Vue.use(VueApollo)
new Vue({
router,
el: "#app",
provide: apolloProvider.provide(),
render: h => h(App)
})
if you created your VUE project using vue-cli > 3 this will cause the issue with this.$apollo equal to undefined.
Related
I need to switch out my backend in-memory DB for testing due to memory issues. Below is my code
import { fireEvent, render, screen, waitFor } from "#testing-library/react";
import userEvent from "#testing-library/user-event";
import App from "App";
import axios from "axios";
import MockAdapter from "axios-mock-adapter";
import { AccessLevel, ResponseApi, SystemUserApi } from "types";
let mock: MockAdapter;
beforeAll(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.reset();
});
beforeEach(() => {
jest.resetModules();
});
describe("<App />", () => {
test("login", async () => {
mock.onPost('/Hello').reply(200, getPost);
const result = render(<App />);
const user = userEvent.setup();
const btnLogin = screen.getByText(/Login/i) as HTMLButtonElement;
await userEvent.click(btnLogin);
let btnOk = screen.queryByText(/OK/i) as HTMLButtonElement;
expect(btnOk.disabled).toBe(true);
let btnCancel = screen.getByText(/Cancel/i) as HTMLButtonElement;
expect(btnCancel.disabled).toBe(false);
fireEvent.change(screen.getByLabelText(/Access Code/i) as HTMLInputElement, { target: { value: 'USER' } });
expect(btnOk.disabled).toBe(false);
await userEvent.click(btnOk);
//At this point I was expecting the onPost to be clicked
});
});
function getPost(config: any): any {
console.log(config);
debugger;
return {
data: {
access_code: 'USER'.toUpperCase(),
access_level: AccessLevel.USER ,
lock_level:true
} as SystemUserApi,
error: false,
} as ResponseApi
}
Deep down in the is a call axios post to /Hello but my function within the test is not called. I do not know if it has to do with the actual call being axios.request vs axios.post. I have tried switching to mock.onAny, but that did not seem to work. Not sure what to do here.
im trying to to convert below code snippet to JEST unit testing but its throwing error please help me out in resolving it
import React from 'react'
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import IdleTimer from 'react-idle-timer';
import { ApolloProvider } from '#apollo/react-hooks';
import Dashboard from '../pages/Dashboard';
import Loader from '../components/Loader';
import Alert from '../components/Alert';
import NoAccess from '../pages/NoAccess';
import { GQL } from '../services/GQL';
import { IdleTimeOutModal } from './IdleTimeoutModal';
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../App.scss';
import '../assets/css/loader.scss';
import AuthenticatedRoute from '../guards/AuthenticatedRoute';
import auth from '../services/Auth';
import { connect } from 'react-redux';
class Layout extends React.Component {
constructor(props){
super(props);
this.state = {
timeout:1000 * 900 * 1,
showModal: false,
userLoggedIn: window.localStorage.getItem('loginUser'),
isTimedOut: false,
}
this.idleTimer = null
this.onAction = this._onAction.bind(this)
this.onActive = this._onActive.bind(this)
this.onIdle = this._onIdle.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleLogout = this.handleLogout.bind(this)
}
_onAction(e) {
// console.log('user did something', e)
this.setState({isTimedOut: false})
}
_onActive(e) {
// console.log('user is active', e)
this.setState({isTimedOut: false})
}
_onIdle(e) {
// console.log('user is idle', e)
const isTimedOut = this.state.isTimedOut
if (isTimedOut) {
this.setState({showModal: false})
window.localStorage.setItem('loginUser', 'false');
} else {
this.setState({showModal: true})
this.idleTimer.reset();
this.setState({isTimedOut: true})
}
}
handleClose() {
this.setState({showModal: false})
}
handleLogout() {
this.setState({showModal: false})
auth.signout();
}
render(){
// console.log(window.location)
const {match} = window.location.href;
// const { match } = this.location
return(
<>
<IdleTimer
ref={ref => { this.idleTimer = ref }}
element={document}
onActive={this.onActive}
onIdle={this.onIdle}
onAction={this.onAction}
debounce={250}
timeout={this.state.timeout} />
<div className="">
<ApolloProvider client={GQL}>
<Router>
<Switch>
{/* <Route component={NoAccess} path="/no-access" exact={true} /> */}
<AuthenticatedRoute path={`${window.location.pathname}`} component={Dashboard} />
</Switch>
</Router>
{/* <Loader isOpen={loader.isLoading} /> */}
{/* <Alert /> */}
</ApolloProvider>
<IdleTimeOutModal
showModal={this.state.showModal}
handleClose={this.handleClose}
handleLogout={this.handleLogout}
/>
</div>
</>
)
}
}
***JEST throwing error while converting to JEST - ShallowWrapper::state() can only be called on class components
jest help***
export default connect((props) =>({
match: props.uiel.isRequired,
history: props.uiel.isRequired
}))(Layout);
import React from 'react';
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import { render, cleanup, fireEvent } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect';
import Enzyme, { shallow, mount } from 'enzyme';
import Layout from './Layout';
import Adapter from 'enzyme-adapter-react-16';
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import { IdleTimeOutModal } from './IdleTimeoutModal';
import { wrap } from 'module';
Enzyme.configure({ adapter: new Adapter() })
const mockStore = configureMockStore();
let handleLogout:any;
let showModal: any;
let handleClose:any;
let remainingTime:any;
let _onAction:any;
let _onIdle:any;
let _onActive:any;
let idleTimer:any;
describe("Render Layout Component", ()=>{
let store;
let wrapperlayout:any;
beforeEach(()=>{
store = mockStore({
loader: false
});
wrapperlayout = shallow(
<Provider store={store}>
<Layout />
</Provider>
);
});
it('should render the value of color', () => {
wrapperlayout.setProps({ timeout:1000 * 900 * 1 });
wrapperlayout.setProps({ showModal: false });
wrapperlayout.setProps({ userLoggedIn: window.localStorage.getItem('loginUser') });
wrapperlayout.setProps({ isTimedOut: false });
//expect(wrapper.state('color')).toEqual('transparent');
});
it("should increment index - function test", () => {
//const app = shallow(<Normal />);
expect(wrapperlayout.state("isTimedOut")).toEqual('false');
wrapperlayout.instance()._onAction();
expect(wrapperlayout.state("isTimedOut")).toEqual('false');
});
test("Render Modal Layout", ()=>{
expect(wrapperlayout.exists()).toBe(true);
});
});
I want to create a Mock API Server for my Jest tests so that I can define all my backend endpoints and create responses and authentication checks.
I have managed to set up the server and routes by following some of the source code from Chris Fritz "Vue-Enterprice-boilerplate":
https://github.com/chrisvfritz/vue-enterprise-boilerplate/tree/master/tests/unit
// jest.config.js
const _ = require("lodash");
process.env.MOCK_API_PORT = process.env.MOCK_API_PORT || _.random(9000, 9999);
module.exports = {
preset: "#vue/cli-plugin-unit-jest",
setupFiles: ["./tests/unit/setup"],
globalSetup: "<rootDir>/tests/unit/global-setup",
globalTeardown: "<rootDir>/tests/unit/global-teardown",
testMatch: ["**/(*.)spec.js"],
moduleFileExtensions: ["js", "jsx", "json", "vue"],
transform: {
"^.+\\.vue$": "vue-jest",
"^.+\\.js$": "babel-jest",
".+\\.(css|scss|jpe?g|png|gif|webp|svg|mp4|webm|ogg|mp3|wav|flac|aac|woff2?|eot|ttf|otf)$":
"jest-transform-stub"
},
transformIgnorePatterns: ["/node_modules/(?!vue-spinner)"],
testURL: process.env.API_BASE_URL || `http://localhost:${process.env.MOCK_API_PORT}`
};
The server runs when the tests starts and I can console log the route files.
I just don't know how the axios call from my Vuex would go with the mock API instead of the real one.
Might need to import axios somewhere in the test to prevent the development URL to be used?
/tests/mock-api/routes/auth.js
const Users = require("../resources/users");
module.exports = app => {
console.log('I can see this during tests!');
app.post("/api/v1/login", async (req, res) => {
console.log("I don't see this..");
await Users.authenticate(req.body)
.then(user => {
res.json(user);
})
.catch(error => {
res.status(401).json({ message: error.message });
});
});
});
// /views/Login.spec.js
import Vue from "vue";
import Vuelidate from "vuelidate";
import Login from "#/views/Login";
import BaseButton from "#/components/Globals/_base-button.vue";
import BaseInput from "#/components/Globals/_base-input.vue";
import BaseLabel from "#/components/Globals/_base-label.vue";
import flushPromises from "flush-promises";
import store from "#/store";
import { shallowMount } from "#vue/test-utils";
Vue.use(Vuelidate);
describe("#/views/Login", () => {
// other tests..
it("redirects to posts on successful login", async () => {
const wrapper = shallowMount(Login, { store, stubs: { BaseInput, BaseButton, BaseLabel } });
wrapper.vm.$v.$touch();
const spyDispatch = jest.spyOn(wrapper.vm.$store, "dispatch");
const username = wrapper.find("#username");
const password = wrapper.find("#password");
username.element.value = "johndoe#email.com";
password.element.value = "passwordz";
username.trigger("input");
password.trigger("input");
await wrapper.find("#submitBtn").trigger("click.prevent");
await wrapper.vm.$nextTick();
await flushPromises();
await expect(spyDispatch).toHaveBeenCalledWith("auth/login", {
username: username.element.value,
password: password.element.value
});
// #TODO add expect for redirect as well
});
// /store/auth.js (vuex)
export const actions = {
async login({ commit }, { username, password }) {
console.log("I see this");
const response = await axios.post("/login",
{ username, password }, { withCredentials: true });
console.log("I don't see this");
// #TODO error handling
if (!response) return;
commit("setUser", { ...response.data.user });
router.push({ name: "Posts" });
},
The login action gets called but I don't get passed the axios.post.
Do I need to import axios somewhere to make sure I get a fresh instance? (Vuex uses one I set the baseURL and headers)
All the other tests and logic works except this.
i have a react component with function as below that calls api service using axios.I would want to know how to write unit test using enzyme,sinon and chai.
import React from 'react';
import es6BindAll from 'es6bindall';
import { browserHistory } from 'react-router';
import axios from 'axios';
export default class Header extends React.Component {
constructor() {
super();
es6BindAll(this,['handleLogoutClick']);
}
handleLogoutClick(e) {
e.preventDefault();
let that = this;
this.serverRequest = axios({
url: 'Url_to_call',
method: 'post'
}).then(function (successData) {
browserHistory.push("nextPage to navigate");
}.bind(that));
}
render(){
return(
<div className="columns large-12 header-container">
<h6 className="logout" onClick={this.handleLogoutClick}>Logout</h6>
</div>
</div>
)
}
}
I have written test case as below
import React from 'react';
import { mount,shallow } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import '../testUtils';
import Header from '../../components/Common/Header';
describe('(Container) Header', () => {
const wrapper = shallow(<Header />);
let sandbox;
let server;
beforeEach(() => {
sandbox = sinon.sandbox.create();
server = sandbox.useFakeServer();
});
afterEach(() => {
server.restore();
sandbox.restore();
});
it('Logout link to be present', () => {
expect(wrapper.find('.logout')).to.exist;
});
it('simulates logout clicks', () => {
wrapper.find('h6').filter('.logout').simulate('click',{preventDefault() {} });
expect(wrapper.instance().handleLogoutClick).to.have.been.called;
});
});
And configured testUtils.js as below
var jsdom = require('jsdom').jsdom;
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
global[property] = document.defaultView[property];
}
});
global.window.loggedInUserData = {userName: 'TestName'};
global.navigator = {
userAgent: 'node.js'
};
Please let me know how to test axios and mock browserHistory.I am not running on any browser to test so please let me know how to mock
Thanks
You need to stub browserHistory using sinon as below,
import { browserHistory } from 'react-router';
import { stub } from 'sinon';
const browserHistoryPushStub = stub(browserHistory, 'push', () => { });
For mocking axios requests, you can use Moxios
I've recently made an ng2 (using 2.0.1) app with multiple components and services. I'm in the middle of testing (Karma Jasmine) my HeaderComponent which contains my UserService (Which uses an extended Http class).
I've replicated simple tests from the Angular.io Docs to spy on a service and wait for after component initialization to check if the service function has been fired and its content. Every time I run the last test using fakeAsync (and async), which checks the content of the currentUser variable in header.component, I receive the following error...
Error: Uncaught (in promise): Error: Template parse errors:
'header-section' is not a known element:
1. If 'header-section' is an Angular component, then verify that it is part of this module.
2. If 'header-section' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("
[ERROR ->]<header-section></header-section>
<router-outlet></router-outlet>
<footer-section></footer-sectio"): AppComponent#1:2
'router-outlet' is not a known element:
1. If 'router-outlet' is an Angular component, then verify that it is part of this module.
2. If 'router-outlet' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("
<header-section></header-section>
[ERROR ->]<router-outlet></router-outlet>
<footer-section></footer-section>"): AppComponent#2:2
'footer-section' is not a known element:
1. If 'footer-section' is an Angular component, then verify that it is part of this module.
2. If 'footer-section' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schemas' of this component to suppress this message. ("
<header-section></header-section>
<router-outlet></router-outlet>
[ERROR ->]<footer-section></footer-section>"): AppComponent#3:2
These selectors are from my AppComponent...
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
moduleId: module.id,
template: `
<header-section></header-section>
<router-outlet></router-outlet>
<footer-section></footer-section>`
})
export class AppComponent {
constructor() {}
test(): string {
return 'this is a test';
}
}
My header.component.spec...
import { Http, Request, RequestOptionsArgs, Response, XHRBackend, RequestOptions, ConnectionBackend, Headers } from '#angular/http';
import { HttpIntercept } from '../../services/auth/auth.service';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule, JsonpModule } from '#angular/http';
import { FormsModule } from '#angular/forms';
import { RouterTestingModule } from "#angular/router/testing";
import { appRoutes } from '../../routes';
import { Cookie } from 'ng2-cookies/ng2-cookies';
import { AppComponent } from '../app/app.component';
import { HeaderComponent } from './header.component';
import { FooterComponent } from '../footer/footer.component';
import { HomeComponent } from '../home/home.component';
import { Four0FourComponent } from '../404/four0four.component';
import { UserProfileComponent } from '../user-profile/user-profile.component';
import { UserService } from '../../services/user/user.service';
import { ClockService } from '../../services/clock/clock.service';
import { Observable } from 'rxjs/Observable';
import { TestBed, async, fakeAsync, tick } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { User } from '../../models/user/user.model';
class MockRouter { public navigate() { }; }
describe('HeaderComponent Test', () => {
let fixture;
let comp;
let userService;
let spy;
let user = new User({
_id: 123456,
userName: 'testName',
firstName: 'testFirst',
lastName: 'testLast',
email: 'test#email.com',
create: 'now',
role: 'user'
});
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
BrowserModule,
HttpModule,
FormsModule,
JsonpModule,
RouterTestingModule.withRoutes(appRoutes)
],
declarations: [
HomeComponent,
UserProfileComponent,
Four0FourComponent,
FooterComponent,
HeaderComponent,
AppComponent
],
providers: [
{
provide: Http,
useFactory: (
backend: XHRBackend,
defaultOptions: RequestOptions) =>
new HttpIntercept(backend, defaultOptions),
deps: [XHRBackend, RequestOptions]
},
Cookie
]
});
fixture = TestBed.createComponent(HeaderComponent);
comp = fixture.componentInstance;
userService = fixture.debugElement.injector.get(UserService);
spy = spyOn(userService, 'getMe')
.and.returnValue(Observable.of(user));
});
it('should instantiate component', () => {
expect(fixture.componentInstance instanceof HeaderComponent).toBe(true);
});
it('should not show currentUser before OnInit', () => {
expect(spy.calls.any()).toBe(false, 'getMe not yet called');
});
it('should still not show currentUser after component initialized', () => {
// Set cookie token, for the getMe to call
Cookie.set('token', 'test_token_alpha');
fixture.detectChanges();
expect(spy.calls.any()).toBe(true, 'getMe called');
});
//The problem test is bellow
it('should show currentUser after getMe promise', fakeAsync(() => {
fixture.detectChanges();
tick();
fixture.detectChanges();
expect(comp.currentUser).toEqual(user);
}));
});
Here's my header.component...
import { Component } from '#angular/core';
import { Cookie } from 'ng2-cookies/ng2-cookies';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import { UserService } from '../../services/user/user.service';
import { ClockService } from '../../services/clock/clock.service';
import { User } from '../../models/user/user.model';
#Component({
selector: 'header-section',
providers: [
UserService,
ClockService
],
moduleId: module.id,
template: `
<style>
header{
background: rgb(55, 129, 215);
position: relative;
}
.user-sign{
position: absolute;
top:0;
right:0;
margin: 23px 5%;
}
.app-title{
font-family: cursive;
padding: 15px;
text-align: center;
font-size: 36px;
color: white;
}
.user-sign button:hover{
cursor: pointer;
}
.active{
color: orange;
}
</style>
<header>
<a routerLink='/' routerLinkActive='active'>Home</a>
<a routerLink='/profile' routerLinkActive='active'>Profile</a>
<a routerLink='/yoloswaq69420blazeitfgt' routerLinkActive='active'>404</a>
<div class='user-sign'>
<h3 *ngIf='currentUser'>Welcome, {{currentUser.userName}}</h3>
<button *ngIf='!currentUser' type='button' (click)='testRegisterUser()'>Sign up</button>
<button *ngIf='!currentUser' type='button' (click)='testUser()'>Sign in</button>
<button type='button' (click)='logout()'>Sign out</button>
</div>
<h1 class='app-title'>MEA2N Fullstack</h1>
</header>`
})
export class HeaderComponent {
errorMessage: string;
public currentUser: User;
clock = this.clockService.currentTime;
constructor(private userService: UserService, private clockService: ClockService) { }
ngOnInit() {
let token = Cookie.get('token');
if (token)
this.userService.getMe().subscribe(user => this.currentUser = user);
}
login(email: string, password: string) {
this.userService.login(email, password)
.subscribe(() => {
return this.userService.getMe()
.subscribe(user => {
this.currentUser = user;
})
});
}
logout() {
this.userService.logout();
this.currentUser = null;
}
registerUser(username: string, email: string, password: string) {
this.userService.signup(username, email, password)
.subscribe(() => {
return this.userService.getMe()
.subscribe(user => {
this.currentUser = user;
})
});
}
testUser() {
this.login('jc.thomas4214#gmail.com', 'flight1855');
}
testRegisterUser() {
this.registerUser('Jason', 'jc.thomas4214#gmail.com', 'flight1855');
}
}
I've suspected that this error is occurring because of how I'm initializing my TestBed.configureTestingModule().
I've tried...
Reordering both app.module and TestBed module declarations
adding schema: [CUSTOM_ELEMENTS_SCHEMA] to both modules
Since you are unit testing the Header component in this case, there is no need to include other modules and components
TestBed can look like this:
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AppModule
],
providers: [
{provide: UserService, useClass: MockUserService},
{provide: ClockService, useClass: MockClockService}
]
});
fixture = TestBed.createComponent(HeaderComponent);
});
In this example the Services have been mocked but they can be spied too as you have correctly done for the UserService