How to skip mocked image and get real image attributes with Jest? - unit-testing

I am writing unit tests and I want to test an img atrributes. However, when I make an assertion, I get mocked img attributes which is under __mocks__>fileMock.js. Because I mock files, I only get mocked file atrributes. How can I skip mocked files in my tests?
describe('Buttons', () => {
test('Clear filters work after filtering tools, workflows and using searchbar', async () => {
render(<HeaderBar {...defaults} />);
const clearFilterButton = screen.getByRole('button', { name: 'Clear Filters' });
const toolsButton = screen.getByRole('button', { name: 'TOOLS' });
const selectedTools = await within(toolsButton).findByRole('img');
expect(selectedTools).toHaveAttribute('src', 'images/tools-selected.png');
});
And test result is :
Buttons › Clear filters work after filtering tools, workflows and using searchbar
expect(element).toHaveAttribute("src", "images/tools-selected.png") // element.getAttribute("src") === "images/tools-selected.png"
Expected the element to have attribute:
src="images/tools-selected.png"
Received:
src="test-file-stub"
39 | const toolsButton = screen.getByRole('button', { name: 'TOOLS' });
40 | const selectedTools = await within(toolsButton).findByRole('img');
> 41 | expect(selectedTools).toHaveAttribute('src', 'images/tools-selected.png');
I need to test real image, and skip mocking that img in my test.

It sounds like you have a manual user module mock defined in a __mock__ folder next to your actual code.
In that case the mock is used in any test file where you call jest.mock('moduleName') unless automock is set to true in which case the mock will always be used.
If you are explicitly mocking the file using jest.mock('moduleName') then simply remove that from the test file where you want to use the actual code instead of the mock.
If you have automock set to true in your Jest config then you can tell Jest to use the original code file in a given test by using jest.unmock('moduleName').

Related

How to run a single test suite in Jest?

I have many test suites. I wanna to run a singe one and skip all the others, and I would like to do this on the code level.
I know I can do this using .only() and .skip() in a test file, but that supports only the tests / describes defined in that file.
Is there a way to do this globally? Like is there something like .only() which - when called on the top level describe - runs only that test suite and all others are skipped?
Or: when called on a single test ( it().only() ), then only that test runs and nothing else?
I see nothing like this in the API, but maybe Jest can be configured to work this way?
Is this possible with Jest or is this something I can only do via CLI?
If I understand correctly: You want to run just one test suite/file.
You can do this from the command line with jest path/to/filename.test.js.
Within a file, you can use test.only(name, fn, timeout) to only run that test. This won't stop Jest from moving on to the next testing file though.
Full Jest CLI docs
As far as I am aware, you cannot do this from within the test file itself.
The closest I can think of would be to set the `testmatch' in Jest's config to a pattern that only matches the file(s) you want run.
package.json
{
"name": "my-project",
"jest": {
"testmatch": "**/my.test.js"
}
}
I think if you adapt this answer: https://stackoverflow.com/a/59487370/14553660 it should give you what you need.
For example:
testsuite.test.js
import { signuptests } from './signup.test.js'
import { logintests } from './login.test.js'
import { logouttests } from './logout.test.js'
describe('Signup', signuptests)
describe.only('Login', logintests)
describe('Logout', logouttests)
signup.test.js
export const signuptests = () => {
it('Should have login elements', () => {});
it('Should Signup', () => {}});
}
login.test.js
export const logintests = () => {
it.only('Should Login', () => {}});
it('etc',()=>{});
}
logout.test.js
export const logouttests = () => {
it('Should Logout', () => {}});
it('etc',()=>{});
}
You will be able to use .only at the top level - in the testsuite file - to determine which test files are run, and you can also use .only within each individual test file (e.g. within login.test.js) to only run one particular test from that file.
I don't know that there is a limit to nesting describe blocks, so I imagine you could even make a 'master-testsuite' that imports different testsuites (which in turn import different test files...etc)

vue testing vuetify input for disabled

I am very new to testing and I'm struggling my way through all this new stuff I am learning. Today I want to write a test for a vuetify <v-text-field> component like this:
<v-text-field
v-model="user.caption"
label="Name"
:disabled="!checkPermissionFor('users.write')"
required
/>
my test should handle the following case:
an active, logged in user has a array in vuex store which has his permissions as a array of strings. exactly like this
userRights: ['dashboard', 'imprint', 'dataPrivacy']
the checkPermissionFor() function is doing nothing else then checking the array above with a arr.includes('x')
after it came out the right is not included it gives me a negotiated return which handles the disabled state on that input field.
I want to test this exact scenario.
my test at the moment looks like this:
it('user has no rights to edit other user overview data', () => {
const store = new Vuex.Store({
state: {
ActiveUser: {
userData: {
isLoggedIn: true,
isAdmin: false,
userRights: ['dashboard', 'imprint', 'dataPrivacy']
}
}
}
})
const wrapper = shallowMount(Overview, {
store,
localVue
})
const addUserPermission = wrapper.vm.checkPermissionFor('users.write')
const inputName = wrapper.find(
'HOW TO SELECT A INPUT LIKE THIS? DO I HAVE TO ADD A CLASS FOR IT?'
)
expect(addUserPermission).toBe(false)
expect(inputName.props('disabled')).toBe(false)
})
big questions now:
how can I select a input from vuetify which has no class like in my case
how can I test for "is the input disabled?"
wrapper.find method accepts a query string. You can pass a query string like this :
input[label='Name'] or if you know the exact index you can use this CSS query too : input:nth-of-type(2).
Then find method will return you another wrapper. Wrapper has a property named element which returns the underlying native element.
So you can check if input disabled like this :
const buttonWrapper = wrapper.find("input[label='Name']");
const isDisabled = buttonWrapper.element.disabled === true;
expect(isDisabled ).toBe(true)
For question 1 it's a good idea to put extra datasets into your component template that are used just for testing so you can extract that element - the most common convention is data-testid="test-id".
The reason you should do this instead of relying on the classes and ids and positional selectors or anything like that is because those selectors are likely to change in a way that shouldn't break your test - if in the future you change css frameworks or change an id for some reason, your tests will break even though your component is still working.
If you're (understandably) worried about polluting your markup with all these data-testid attributes, you can use a webpack plugin like https://github.com/emensch/vue-remove-attributes to strip them out of your dev builds. Here's how I use that with laravel mix:
const createAttributeRemover = require('vue-remove-attributes');
if (mix.inProduction()) {
mix.options({
vue: {
compilerOptions: {
modules: [
createAttributeRemover('data-testid')
]
}
}
})
}
as for your second question I don't know I was googling the same thing and I landed here!

Stencil, Leaflet, unit testing component, gives TypeError: Cannot read property 'deviceXDPI' of undefined

So we are developing a Stenciljs component which wraps leaflet map and adds some additional functionality.
Now obviously we don't want or need to test Leaflet, but instead, just the parts in our wrapper components.
So, using the test examples, we create our tests,
import { LeMap } from "./le-map";
describe("Map component tests", () => {
it("Should build the map component", async () => {
const map = new LeMap();
expect(map).not.toBeNull();
});
});
try and load the components and test the public functions, but we get
TypeError: Cannot read property 'deviceXDPI' of undefined
> 1 | import {Component, Element, Listen, Method, Prop, Watch} from
'#stencil/core';
> 2 | import L from 'leaflet';
| ^
3 |
4 | #Component({
5 | shadow: false,
We believe this message is because the test is trying to render leaflet, and because it's not a true browser, it can't detect a view so throwing this error, so we've tried to mock leaflet in the tests, but still get the same problem.
We're tried to mock the leaflet module by using jest mocking
jest.genMockFromModule('leaflet');
but this made no diffrence
Only idea I've had is to separate the logic from the components, but that feels wrong, as we'd just be doing this for purpose of testing.
Versions in use are: leaflet: 1.3.4, #stencil: 0.15.2, jest: 23.4.2
Any other suggestions?
Further investigation with, thanks to #skyboyer 's suggestions, leads me to this line of the leaflet core browser.js file
leads me to this line of the leaflet core browser.js file
export var retina = (window.devicePixelRatio || (window.screen.deviceXDPI/window.screen.logicalXDPI)) > 1;
But I'm unable to mock the screen property of window as I get the following error
[ts] Cannot assign to 'screen' because it is a constant or a read-only property,
so I try the following.
const screen = {
deviceXDPI:0,
logicalXDPI:0
}
Object.defineProperty(window, 'screen', screen);
Object.defineProperty(window, 'devicePixelRatio', 0);
Same error, completely ignores this, so I try over riding the export.
jest.spyOn(L.Browser,'retina').mockImplementation(() => false);
No joy either, so tried
L.Browser.retina = jest.fn(() => false);
but get it tells me it's a constant and can't be changed (yet the implication stats var so ¯_(ツ)_/¯ )
Anything else I can try?
Further update,
I've managed to mock the window, but this sadly doesn't solve it.
const screenMock = {
deviceXDPI: 0,
logicalXDPI: 0
}
const windowMock = {
value: {
'devicePixelRatio': 0,
'screen': screenMock
}
}
Object.defineProperty(global, 'window', windowMock);
If I console log this, I get the right properties but as soon as I test the instantiation of the component it fails with
TypeError: Cannot read property 'deviceXDPI' of undefined
Reading around it seems Leaflet doesn't check for a DOM and just tries to render anyway, I can't see anyway around this, I saw a leaflet-headless package, but I don't know how I could swap them out just for testing.
Think I will need to look at another strategy for testing, probably protractor.
Found a solution, not fully tested yet, but the tests pass.
I did it by creating a
__mocks__
directory at the same level as the node_modules directory.
created a file called leaflet.js in it. It's a simple file it just contains.
'use strict';
const leaflet = jest.fn();
module.exports = leaflet;
then in my test file (le-map.spec.ts) I just added
jest.mock('leaflet')
before the imports
and now my test passes.
I tried doing this in the test itself but that just gave me the same error, it must be something in the loading sequence which means it has to be manually mocked beforehand.
Hope this helps others, it's been driving me mad for weeks.

Unit testing a directive that defines a controller in AngularJS

I'm trying to test a directive using Karma and Jasmine that does a couple of things. First being that it uses a templateUrl and second that it defines a controller. This may not be the correct terminology, but it creates a controller in its declaration. The Angular application is set up so that each unit is contained within its own module. For example, all directives are included within module app.directive, all controllers are contained within app.controller, and all services are contained within app.service etc.
To complicate things further, the controller being defined within this directive has a single dependency and it contains a function that makes an $http request to set a value on the $scope. I know that I can mock this dependency using $httpBackend mock to simulate the $http call and return the proper object to the call of this function. I've done this numerous times on the other unit tests that I've created, and have a pretty good grasp on this concept.
The code below is written in CoffeeScript.
Here is my directive:
angular.module('app.directive')
.directive 'exampleDirective', [() ->
restrict: 'A'
templateUrl: 'partials/view.html'
scope: true
controller: ['$scope', 'Service', ($scope, Service) ->
$scope.model = {}
$scope.model.value_one = 1
# Call the dependency
Service.getValue()
.success (data) ->
$scope.model.value_two = data
.error ->
$scope.model.value_two = 0
]
]
Here is the dependency service:
angular.module("app.service")
.factory 'Service', ['$http', ($http) ->
getValue: () ->
options.method = "GET"
options.url = "example/fetch"
$http _.defaults(options)
Here is the view:
<div>
{{model.value_one}} {{model.value_two}}
</div>
I've simplified this quite a bit, as my goal is only to understand how to wire this up, I can take it from there. The reason I'm structuring it this way is because I did not initially create this. I'm working on writing tests for an existing project and I don't have the ability to configure it any other way. I've made an attempt to write the test, but cannot get it to do what i want.
I want to test to see if the values are being bound to the view, and if possible to also test to see if the controller is creating the values properly.
Here is what I've got:
'use strict'
describe "the exampleDirective Directive", ->
beforeEach module("app.directive")
beforeEach module("app/partials/view.html")
ServiceMock = {
getValue : () ->
options.method = "GET"
options.url = "example/fetch"
$http _.defaults(options)
}
#use the mock instead of the service
beforeEach module ($provide) ->
$provide.value "Service", ServiceMock
return
$httpBackend = null
scope = null
elem = null
beforeEach inject ($compile, $rootScope, $injector) ->
# get httpBackend object
$httpBackend = $injector.get("$httpBackend")
$httpBackend.whenGET("example/fetch").respond(200, "it works")
#set up the scope
scope = $rootScope
#create and compile directive
elem = angular.element('<example-directive></example-directive>')
$compile(elem)(scope)
scope.$digest()
I don't know how close I am, or if this is even correct. I want to be able to assert that the values are bound to the view correctly. I've used Vojtajina's example to set up html2js in my karma.js file to allow me to grab the views. I've done a lot of research to find the answer, but I need some help. Hopefully a programmer wiser than I can point me in the right direction. Thank you.
Create the element in karma, then use the .controller() function with the name of your directive to grab the controller. For your example, replace the last couple of lines with these:
elem = angular.element('<div example-directive></div>');
$compile(elem)($rootScope);
var controller = elem.controller('exampleDirective');
Note, that given how you defined your directive, it should be by attribute, and not as an element. I'm also not 100% sure, but I don't think you need the scope.$digest; usually I just put anything that needs to be applied into a scope.$apply(function() {}) block.

using mocha testing with cloud9, execute mocha tests from node.js

I was wondering if there is a way to execute mocha tests programmatically from node.js so that I can integrate unit tests with Cloud 9. The cloud 9 IDE has a nice feature where whenever a javascript files is saved, it looks for a file with the same name, ending with either "_test" or "Test" and runs it automatically using node.js. For example it has this code snippet in a file demo_test.js which automatically runs.
if (typeof module !== "undefined" && module === require.main) {
require("asyncjs").test.testcase(module.exports).exec()
}
Is there something like this I could use to run a mocha test? Something like a mocha(this).run()?
The essentials to programmatically run mocha:
Require mocha:
var Mocha = require('./'); //The root mocha path (wherever you git cloned
//or if you used npm in node_modules/mocha)
Instatiate call the constructor:
var mocha = new Mocha();
Add test files:
mocha.addFile('test/exampleTest'); // direct mocha to exampleTest.js
Run it!:
mocha.run();
Add chained functions to programmatically deal with passed and failed tests. In this case add a call back to print the results:
var Mocha = require('./'); //The root mocha path
var mocha = new Mocha();
var passed = [];
var failed = [];
mocha.addFile('test/exampleTest'); // direct mocha to exampleTest.js
mocha.run(function(){
console.log(passed.length + ' Tests Passed');
passed.forEach(function(testName){
console.log('Passed:', testName);
});
console.log("\n"+failed.length + ' Tests Failed');
failed.forEach(function(testName){
console.log('Failed:', testName);
});
}).on('fail', function(test){
failed.push(test.title);
}).on('pass', function(test){
passed.push(test.title);
});
Your mileage may vary, but I concocted the following one-liner a while back and it has served me pretty well:
if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);
Additionally, if you want it to be output in asyncjs format that Cloud9 is expecting, you'll need to provide a special reporter. Here's a really simple example of what a simple reporter would look like:
if (!module.parent){
(new(require("mocha"))()).ui("exports").reporter(function(r){
var i = 1, n = r.grepTotal(r.suite);
r.on("fail", function(t){ console.log("\x1b[31m[%d/%d] %s FAIL\x1b[0m", i++, n, t.fullTitle()); });
r.on("pass", function(t){ console.log("\x1b[32m[%d/%d] %s OK\x1b[0m", i++, n, t.fullTitle()); });
r.on("pending", function(t){ console.log("\x1b[33m[%d/%d] %s SKIP\x1b[0m", i++, n, t.fullTitle()); });
}).addFile(__filename).run(process.exit);
}