Is it possible to use Recompose for the Query component of react-apollo?
https://www.apollographql.com/docs/react/essentials/queries.html#basic
I was thinking of something like this:
const props = {component:"Query", query: gql(ListResults), children: ViewResults};
export default withProps(props)(componentFromProp('component'))
You can compose in a query instead of using the Query component.
Using the example from the link you posted.
import { compose } from 'recompose';
import gql from 'graphql-tag';
import { graphql } from 'react-apollo';
const Dogs = ({ data, onDogSelected }) => (
<select name="dog" onChange={onDogSelected}>
{data.dogs.map(dog => (
<option key={dog.id} value={dog.breed}>
{dog.breed}
</option>
))}
</select>
);
const GET_DOGS = gql`
{
dogs {
id
breed
}
}
`;
const getDogsQuery = graphql(GET_DOGS, {
options: props => ({
fetchPolicy: props.fetchPolicy // example of passing to the query from props.
})
});
export default compose(getDogsQuery)(Dogs); // { data } is now a prop with the query results.
Related
I am using apollo/client and graphql-tools/mock to auto mock graphql queries and test React Native components that use them. My schema is generated from an introspection query created by graphql-codegen. For the most part, my queries are getting mocked by addMocksToSchema just fine. However I have a query that is not returning any mock data.
The query is paginated and doesn't follow the same structure of the examples in the docs (https://www.graphql-tools.com/docs/mocking). Instead of having a query with a node that has a field that is a connection type, the connection is returned from the query. This means I can't use relayStylePaginationMock to mock my function because the resolver argument of addMocksToSchema expects the nodes to be objects not functions(function is the return type of relayStylePaginationMock).
In the below code I have tried overriding the newsPost query with a resolver, but I can't figure out how to get the NewsPostEdges from the store and put them in my mock. Everything I have tried has broken the mock and caused it to return undefined for the whole mocked query.
Why does a paginated mock not work by default?
How can I mock this query?
Schema:
type Query {
newsPost: NewsPostConnection
}
type NewsPostConnection {
totalCount: Int
edges: [NewsPostEdge]!
pageInfo: PageInfo!
}
type NewsPostEdge {
node: NewsPostNode
cursor: String!
}
type NewsPostNode {
newsPostId: Int!
isPinned: Boolean!
label: String
title: String
content: String
postType: NewsPostType!
createdDate: DateTime
createdDateTime: String
creator: UserNode!
}
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
endCursor: String
startCursor: String
}
News Posts query:
query NewsPosts(
$after: String
$first: Int
$newsPostId: Filter_ID
$sort: [NewsPostSortEnum]
$isPinned: Filter_Boolean
) {
newsPosts(
after: $after
first: $first
newsPostId: $newsPostId
sort: $sort
isPinned: $isPinned
) {
pageInfo {
hasNextPage
endCursor
}
edges {
post: node {
newsPostId
postType
isPinned
label
createdDateTime
creator {
initials
avatarUrl
displayName
}
content
}
}
}
}
newsPostsContent.test.tsx
import React from 'react';
import { waitFor } from '#testing-library/react-native';
import { PartialDeep } from 'type-fest';
import { faker } from '#faker-js/faker';
import { createFakeUser, render } from '#root/unit-tests/#util';
import { NewsPostNode, NewsPostType } from '#root/src/generated';
import NewsPostContent from '../NewsPostContent';
const mocks = {
NewsPostNode: (): PartialDeep<NewsPostNode> => {
const postId = faker.random.numeric(4);
const createdDate = faker.date.recent(10);
return {
postId,
isPinned: true,
label: 'test',
content: `<div><p>${faker.random.words(10)}</p></div>`,
postType: NewsPostType.Announcement,
createdDate: createdDate.toISOString(),
createdDateTime: createdDate.toISOString(),
};
},
UserNode: createUserPerson(),
};
describe('Dashboard News', () => {
it('renders dashboard news', async () => {
const { getByTestId, debug } = render(
<NewsPostContent />,
mocks,
);
await waitFor(() => [debug(), expect(getByTestId('newsPostContent:Card')).toBeDefined()]);
});
});
NewsPostsContetnt.tsx
const NewsPostContent = () => {
const [newsPostList, setNewsPostList] = useState<PartialDeep<NewsPostNode>[]>([])
const {
data,
loading,
refetch: refetchPosts,
} = useNewsPostsQuery({
variables: { first: MAX_POSTS, isPinned: true, sort: [PostSortEnum.CreatedDateDesc] },
});
console.log(data); // <-- returns undefined when mock breaks
useEffect(() => {
const newsPostEdges = data?.newsPosts?.edges ?? [];
const newsPostNodes = newsPostEdges.reduce((posts, newsPostNode) => {
if (newsPostNode?.post) {
posts.push(newsPostNode.post);
}
return posts;
}, [] as PartialDeep<NewsPostNode>[]);
setNewsPostList(newsPostNodes);
}, [data]);
return (
{<View>
// Component UI to render posts
</View>}
)
}
AutoMockedProvider.tsx
import React from 'react';
import { ApolloProvider, ApolloClient, InMemoryCache } from '#apollo/client';
import { buildClientSchema } from 'graphql';
import {
addMocksToSchema,
createMockStore,
IMocks,
IMockStore,
relayStylePaginationMock,
} from '#graphql-tools/mock';
import { SchemaLink } from '#apollo/client/link/schema';
import { faker } from '#faker-js/faker';
const introspectionResult = require('../../src/generated/introspection.json');
const defaultMocks = {
Date: () => faker.date.recent().toISOString(),
DateTime: () => faker.date.recent().toISOString(),
};
const resolvers = (store: IMockStore) => ({
Query: {
newsPosts: (root, { isPinned, after, first, postId, sort }) => {
return {
edges: (ref) => {
const connectionsRef = store.get('NewsPostConnection');
const edgesRef = store.get(connectionsRef, 'edges');
return edgesRef; // <-- this breaks the mock
},
pageInfo: {
endCursor: null,
hasNextPage: false,
},
};
},
},
});
const AutoMockedProvider = ({
mocks = {},
children,
}: React.PropsWithChildren<{ mocks?: IMocks }>) => {
const schema = buildClientSchema(introspectionResult);
const store = createMockStore({ mocks: { ...defaultMocks, ...mocks }, schema });
const schemaWithMocks = addMocksToSchema({
schema,
mocks: {
...defaultMocks,
...mocks,
},
resolvers,
preserveResolvers: false,
store,
});
const client = new ApolloClient({
link: new SchemaLink({ schema: schemaWithMocks }),
cache: new InMemoryCache(),
});
return <ApolloProvider client={client}>{children}</ApolloProvider>;
};
export default AutoMockedProvider;
I'm trying to get Apollo gql to load more posts after clicking a button. So it would load the next 15 results, every time you click - load more.
This is my current code
import Layout from "./Layout";
import Post from "./Post";
import client from "./ApolloClient";
import { useQuery } from "#apollo/react-hooks"
import gql from "graphql-tag";
const POSTS_QUERY = gql`
query {
posts(first: 15) {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
const Posts = props => {
let currPage = 0;
const { posts } = props;
const { loading, error, data, fetchMore } = useQuery(
POSTS_QUERY,
{
variables: {
offset: 0,
limit: 15
},
fetchPolicy: "cache-and-network"
});
function onLoadMore() {
fetchMore({
variables: {
offset: data.posts.length
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return Object.assign({}, prev, {
posts: [...prev.posts, ...fetchMoreResult.posts]
});
}
});
}
if (loading) return (
<div className="container mx-auto py-6">
<div className="flex flex-wrap">
Loading...
</div>
</div>
);
if (error) return (
<div className="container mx-auto py-6">
<div className="flex flex-wrap">
Oops, there was an error :( Please try again later.
</div>
</div>
);
return (
<div className="container mx-auto py-6">
<div className="flex flex-wrap">
{data.posts.nodes.length
? data.posts.nodes.map(post => <Post key={post.postId} post={post} />)
: ""}
</div>
<button onClick={() => { onLoadMore() }}>Load More</button>
</div>
);
};
export default Posts;
When you click load more it refreshes the query and console errors
Invalid attempt to spread non-iterable instance
I have been loading for solutions but a lot of the examples are previous or next pages like traditional pagination. Or a cursor based infinite loader which I don't want. I just want more posts added to the list onClick.
Any advise is appreciated, thank you.
Your current POSTS_QUERY it isn't accepting variables, so first you need change this:
const POSTS_QUERY = gql`
query postQuery($first: Int!, $offset: Int!) {
posts(first: $first, offset: $offset) {
nodes {
title
slug
postId
featuredImage {
sourceUrl
}
}
}
}
`;
Now, it will use the variables listed in your useQuery and fetchMore.
And to finish the error is because updateQuery isn't correct, change it to:
function onLoadMore() {
fetchMore({
variables: {
offset: data.posts.nodes.length
},
updateQuery: (prev, { fetchMoreResult }) => {
if (!fetchMoreResult) return prev;
return { posts: { nodes: [...prev.posts.nodes, ...fetchMoreResult.posts.nodes] } };
});
}
});
}
I would suggest useState hook to manage a variable that stores current offset in the dataset, place a useEffect to watch changes to that offset, the offset value in passed as query variable to load data. Remove fetchmore, useEffect hook will do the job.
When user clicks on load more button, you just need to update offset value, that will trigger the query and update data.
const [offset,setOffset] = React.useState(0)
const [results, setResults] = React.useState([])
const { loading, error, data } = useQuery(
POSTS_QUERY,
{
variables: {
offset: offset,
limit: 15
},
fetchPolicy: "cache-and-network"
}
);
React.useEffect(() => {
const newResults = [...results, ...data]
setResults(newResults)
}, [data])
function onLoadMore() {
setOffset(results.data.length)
}
I have a React project with a GraphQL using Apollo client. I am trying to figure out how to change the query result based on search text. I implemented query search in backend and its working perfectly.
But I dont know how to set up filter in React using that same query.
Despite there is tutotial on how to filter on https://www.howtographql.com/react-apollo/7-filtering-searching-the-list-of-links/, it doesnt use ES6 and I literaly dont know how to do it. Im stuck on this filter around 10 days.
I will show you my code.
App.js
import React from 'react';
import HeroesDota from './components/HeroesDota';
import Search from './components/HeroSearch'
import { ApolloProvider } from '#apollo/react-hooks';
import { ApolloClient } from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import { HttpLink } from "apollo-link-http";
const cache = new InMemoryCache();
const link = new HttpLink({
uri: "http://localhost:8000/graphql/"
});
const client = new ApolloClient({
cache,
link
});
const App = () => {
return (
<ApolloProvider client={client}>
<Search />
<HeroesDota />
</ApolloProvider>
)};
export default App;
HeroesDota.js (compoenent)
import React from 'react'
import gql from "graphql-tag";
import { useQuery } from '#apollo/react-hooks';
import '../index.css'
import styled from 'styled-components';
const Images = styled.img`
margin:0;
border: 3px solid #288eea;
display: inline;
width: 90px;
height: 50px;
`
const HEROES_DOTA2 = gql`
query {
heroes {
name
heroType
image
}
}
`;
const HeroesDota = () => {
const { loading, error, data } = useQuery(HEROES_DOTA2);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.heroes.map(({name, heroType, image }) => (
<div className="row" key={Math.random() + 1}>
<div className="column">
<button className="button-hero"><Images className="hero_images" src= {`${image}`} alt={name}></Images></button>
<div className="hero_info">{name} - {heroType}</div>
</div>
</div>
));
}
export default HeroesDota;
HeroSearch.js (compoenent that doesnt work as I expected)
import React, { useState } from 'react'
import gql from "graphql-tag";
import { withApollo } from 'react-apollo'
import Hero from './HeroesDota'
import '../index.css'
const SEARCH_HEROES = gql`
query ($search: String) {
heroes (search: $search) {
id
name
}
}
`;
const Search = () => {
const [heroes, setHeroes] = useState([])
const [search, setSearch] = useState('')
const _executeSearch = async () => {
const { search } = search
const result = await this.props.client.query({
query: SEARCH_HEROES,
variables: { search },
})
const heroes = result.data.heroes.name
setHeroes({ heroes })
}
return (
<div>
<div>
Search
<input
type='text'
onChange={e => setSearch({ search: e.target.value })}
/>
<button onClick={() => _executeSearch()}>OK</button>
</div>
{heroes.map((hero, index) => (
<Hero key={hero.id} hero={hero} index={index} />
))}
</div>
)
}
export default withApollo(Search)
After U oress OK button to exectue search i get following error.
Unhandled Rejection (ReferenceError): Cannot access 'search' before initialization.
If I try to do something similar like I did in Component HeroesDota i still cant make it.
Does anyone know how to filter query in React using es6, not class based compoenent like they did on this tutorial.
Thanks
const Search = (props) => {
props.client.query()
...
}
or
const Search = ({ client }) => {
client.query()
...
}
Although I would also recommend you use the the new hooks syntax.
Maybe I misunderstood what this package does, but I assumed that it would read cached responses and help with offline application functionality.
import React from 'react'
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'
export const DATA_QUERY = gql`
query Data {
me {
name
bestFriend {
name
}
}
}
`
const options = () => ({
fetchPolicy: 'cache-only'
})
const withData = graphql(DATA_QUERY, { options })
export const Start = ({ data }) =>
data.loading ? (
'loading!'
) : data.me ? (
<div>
{console.log('data', data)}
<h3>Me: {data.me.name}</h3>
<p>Best friend: {data.me.bestFriend.name}</p>
</div>
) : (
'no data'
)
export default withData(Start)
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { ApolloProvider } from 'react-apollo'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { HttpLink } from 'apollo-link-http'
import { persistCache } from 'apollo-cache-persist'
const cache = new InMemoryCache()
persistCache({
cache,
storage: window.localStorage,
debug: true
})
export const client = new ApolloClient({
link: new HttpLink({ uri: 'https://v9zqq45l3.lp.gql.zone/graphql' }),
cache
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root'));
registerServiceWorker();
I do have the cache in my localStorage
apollo-cache-persist: "{"$ROOT_QUERY.me":{"name":"Bob","bestFriend":{"type":"id","id`enter code here`":"$ROOT_QUERY.me.bestFriend","generated":true}"
When running the above example with fetchPolicy: 'cache-only' the component renders 'no data'. If I do the default fetchPolicy, cache-first, then I get the expected result but I can see the network request is being made.
EDIT: Now works with Daniels answer and this workaround waits for cache to be restored before running the query.
import Start from './Start'
class App extends Component {
state = {
show: false
}
toggle = () =>
this.setState({ show: !this.state.show })
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<br/><br/>
<button onClick={this.toggle}>Show it</button>
<br/><br/>
{this.state.show && <Start />}
</div>
);
}
}
In order to correctly cache and later retrieve the data from the cache, Apollo needs an id (or _id) to work with. If you want to use a different property as the id (like name), you can pass a dataIdFromObject function to your configuration for the in-memory cache:
const cache = new InMemoryCache({
dataIdFromObject: object => {
switch (object.__typename) {
//User is whatever type "me" query resolves to
case 'User': return object.name;
default: return object.id || object._id;
}
}
});
Something like this works, though I wonder if there should be a more elegant solution. Maybe the Retry Link.
https://github.com/apollographql/apollo-cache-persist/issues?utf8=%E2%9C%93&q=is%3Aissue+
export class Index extends Component {
state = {
client: null
}
async componentWillMount() {
const httpLink = new HttpLink({ uri: 'https://v9zqq45l3.lp.gql.zone/graphql' })
const link = ApolloLink.from([ httpLink ])
const cache = new InMemoryCache({
dataIdFromObject: (object) => {
switch (object.__typename) {
// User is whatever type "me" query resolves to
case 'User':
return object.name
default:
return object.id || object._id
}
}
})
await persistCache({
cache,
storage: window.localStorage,
debug: true
})
const client = new ApolloClient({
link,
cache
})
this.setState({ client })
}
render() {
return !this.state.client ? (
null
) : (
<ApolloProvider client={this.state.client}>
<App />
</ApolloProvider>
)
}
}
ReactDOM.render(<Index />, document.getElementById('root'))
I have an Angular2 component that contains a select box that looks like
<select [(ngModel)]="envFilter" class="form-control" name="envSelector" (ngModelChange)="onChangeFilter($event)">
<option *ngFor="let env of envs" [ngValue]="env">{{env}}</option>
</select>
I am trying to write a unit test for the ngModelChange event. This is my latest failing attempt
it("should filter and show correct items", async(() => {
fixture.detectChanges();
fixture.whenStable().then(() => {
el = fixture.debugElement.query(By.name("envSelector"));
fixture.detectChanges();
makeResponse([hist2, longhist]);
comp.envFilter = 'env3';
el.triggerEventHandler('change', {});
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(comp.displayedHistory).toEqual(longhist);
});
});
The part I am having trouble with is that changing the value of the underlying model comp.envFilter = 'env3'; does not trigger the change method. I added el.triggerEventHandler('change', {}); but this throws Failed: Uncaught (in promise): ReferenceError: By is not defined. I cannot find any hints in the documentation... any ideas?
As far as the error. It seems like you just need to import By. This is not something that is global. It should be imported from the following module
import { By } from '#angular/platform-browser';
As far as the testing part, this is what I have been able to figure out. When you change a value in a the component, you need to trigger a change detection to update the view. You do this with fixture.detectChanges(). Once this is done, normally the view should be updated with the value.
From testing something similar to your example, it seems this is not the case though. It seems there is still some asynchronous task going on after the change detection. Say we have the following
const comp = fixture.componentInstance;
const select = fixture.debugElement.query(By.css('select'));
comp.selectedValue = 'a value';
fixture.DetectChanges();
expect(select.nativeElement.value).toEqual('1: a value');
This doesn't seem to work. It appears there is some async going on causing the value not to be set yet. So we need to wait for the async tasks by calling fixture.whenStable
comp.selectedValue = 'a value';
fixture.DetectChanges();
fixture.whenStable().then(() => {
expect(select.nativeElement.value).toEqual('1: a value');
});
The above would work. But now we need to trigger the change event as that doesn't happen automatically.
fixture.whenStable().then(() => {
expect(select.nativeElement.value).toEqual('1: a value');
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
fixture.whenStable().then(() => {
// component expectations here
});
});
Now we have another asynchronous task from the event. So we need to stabilize it again
Below is a complete test that I tested with. It's a refactor of the example from the source code integration tests. They used fakeAsync and tick which is similar to using async and whenStable. But with fakeAsync, you can't use templateUrl, so I though it would be best to refactor it to use async.
Also the source code tests does kind of a double one way testing, first testing model to view, then view to model. While it looks like your test was trying to do kind of a two-way test, from model around back to model. So I refactored it a bit to suite your example better.
import { Component } from '#angular/core';
import { TestBed, getTestBed, async } from '#angular/core/testing';
import { FormsModule } from '#angular/forms';
import { By } from '#angular/platform-browser';
import { dispatchEvent } from '#angular/platform-browser/testing/browser_util';
#Component({
selector: 'ng-model-select-form',
template: `
<select [(ngModel)]="selectedCity" (ngModelChange)="onSelected($event)">
<option *ngFor="let c of cities" [ngValue]="c"> {{c.name}} </option>
</select>
`
})
class NgModelSelectForm {
selectedCity: {[k: string]: string} = {};
cities: any[] = [];
onSelected(value) {
}
}
describe('component: NgModelSelectForm', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ NgModelSelectForm ]
});
});
it('should go from model to change event', async(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
spyOn(comp, 'onSelected');
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
const select = fixture.debugElement.query(By.css('select'));
fixture.whenStable().then(() => {
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(comp.onSelected).toHaveBeenCalledWith({name : 'NYC'});
console.log('after expect NYC');
});
});
}));
});
I found peeskillet's answer very useful but sadly it is a little out of date as the way to dispatch an Event has been changed. I also found there was an unnecessary call to whenStable(). So here is an updated test using peeskillet's setup:
it('should go from model to change event', async(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
spyOn(comp, 'onSelected');
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
const select = fixture.debugElement.query(By.css('select'));
fixture.whenStable().then(() => {
select.nativeElement.dispatchEvent(new Event('change'));
fixture.detectChanges();
expect(comp.onSelected).toHaveBeenCalledWith({name : 'NYC'});
console.log('after expect NYC');
});
}));
Look this example, from angular source (template_integration_spec.ts)
#Component({
selector: 'ng-model-select-form',
template: `
<select [(ngModel)]="selectedCity">
<option *ngFor="let c of cities" [ngValue]="c"> {{c.name}} </option>
</select>
`
})
class NgModelSelectForm {
selectedCity: {[k: string]: string} = {};
cities: any[] = [];
}
it('with option values that are objects', fakeAsync(() => {
const fixture = TestBed.createComponent(NgModelSelectForm);
const comp = fixture.componentInstance;
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}, {'name': 'Buffalo'}];
comp.selectedCity = comp.cities[1];
fixture.detectChanges();
tick();
const select = fixture.debugElement.query(By.css('select'));
const nycOption = fixture.debugElement.queryAll(By.css('option'))[1];
// model -> view
expect(select.nativeElement.value).toEqual('1: Object');
expect(nycOption.nativeElement.selected).toBe(true);
select.nativeElement.value = '2: Object';
dispatchEvent(select.nativeElement, 'change');
fixture.detectChanges();
tick();
// view -> model
expect(comp.selectedCity['name']).toEqual('Buffalo');
}));
Same problem as raised by OP but slightly different code.
Works in Angular 7.
HTML:
<select id="dashboard-filter" class="form-control" name="dashboard-filter" [ngModel]="dashboardFilterValue" (ngModelChange)="onFilterChange($event)"
[disabled]="disabled">
<option *ngFor="let filter of dashboardFilters" [ngValue]="filter.value">{{ filter.name }}</option>
</select>
Unit test:
it('onFilterChange', () => {
// ensure dropdown is enabled
expect(component.disabled).toBe(false)
// spies
spyOn(component, 'onFilterChange').and.callThrough()
spyOn(component.filterChange, 'emit')
// initially the 3rd item in the dropdown is selected
const INITIAL_FILTER_INDEX = 2
// we want to select the 5th item in the dropdown
const FILTER_INDEX = 4
// the expected filter value is the value of the 5th dashboard filter (as used to populate the dropdown)
const EXPECTED_FILTER_VALUE = getDashboardFiltersData.dashboardFilters[FILTER_INDEX].value
// handle on the dropdown
const filterDropdown = fixture.debugElement.query(By.css('select')).nativeElement
// let bindings complete
fixture.whenStable().then(() => {
// ensure filterDropdown.value is stable
expect(filterDropdown.value).toContain(getDashboardFiltersData.dashboardFilters[INITIAL_FILTER_INDEX].value)
// update filterDropdown.value and dispatch change event
filterDropdown.value = filterDropdown.options[FILTER_INDEX].value
filterDropdown.dispatchEvent(new Event('change'))
// check component data
expect(component.dashboardFilterValue).toBe(EXPECTED_FILTER_VALUE)
expect(component.dashboardFilterChangeInProgress).toBe(false)
// check spies
expect(component.onFilterChange).toHaveBeenCalledWith(EXPECTED_FILTER_VALUE)
expect(setDashboardFilterSpy).toHaveBeenCalledWith(EXPECTED_FILTER_VALUE)
expect(component.filterChange.emit).toHaveBeenCalledWith(true)
})
})