How to mock Yii2 component behavior in acceptance test? - selenium

I want to test my application behavior using Selenium. But I want the Yii::$app component behavior can be mocked from the test runner?
Let's say I have a class
Foo extends \yii\base\Component {
public function bar() {
//return something
}
}
And in the configuration I attach as Yii::$app component as Yii::$app->foo.
[
'foo' => [
'class' => 'Foo',
]
]
So the acceptance test works by running a web server and the test runner will run Selenium against the web server.
In the test runner I want to mock the Yii::$app->foo->bar() method so that it will return some string.
Usually when it comes from the database, we can mock by using Fixture. Test runner will fill the database using fixture that we set, and then the application component will read from that database.
How should I do this mock an arbitrary application component in the application run by the web server from the test runner?

Related

Detox - Possible to Force Fail Test?

Is there a way to force a test to fail in Detox? I haven't found anything in the documentation that says this can be the case. I am comparing two IDs that are hidden in an element and screen of my app and if they don't match, I want to fail the test.
if (element.id === screen.id) {
do
}
else {
*fail test*
}
it(`should invite User`, async () => {}
Or is it as easy as just throwing an error? Thanks
Detox itself delegates test logic to a test runner.
Detox delegates the actual JavaScript test-code execution to a dedicated test-runner. It supports the popular Jest and Mocha out of the box.
If you are using jest as the underlying test runner, you could just use its fail method as follows.
if (element.id === screen.id) {
do
}
else {
fail('test fails');
}
In mocha you could use the following function.
assert.fail("actual", "expected", "Error message");
We could also abuse the detox high level api to achieve the same (but less readable).
await waitFor(element(by.id(notVisible.id))).toBeVisible().withTimeout(5);

TestCafe - Shared singleton between testcafe and application

I have an application running with Vue, and I am using testcafe to do end-to-end testing.
MyModule.ts
class MyModule {
public value: string;
constructor() {}
}
export default new MyModule();
Test cafe file
import MyModule from '../models/utils/MyModule';
fixture('Getting Started')
.page('http://localhost:8080/en/home/')
.before(async (ctx) => {
MyModule.value = 'Set by Test Cafe';
});
test('Get to the home page', async (t) => {
....
});
App.vue
<template>.....</template>
<script>
import TeMyModulestModule from '#/test/e2e/models/utils/MyModule';
export default {
created() {
console.log('MyModule.value', MyModule.value);
}
}
</script>
Actual result
MyModule.value undefined
Expected result
MyModule.value 'Set by Test Cafe'
Question
Is it possible to achieve this with testCafe? If so what am I doing wrong?
A TestCafe test fixture is a regular node.js script, and it is executed on the server side. You are trying to share your module between different contexts (node.js server-side and browser client-side).
You can put the specified value into the global window object using the ClientFunction or Inject Client Scripts approach and obtain it from the Vue script.

Can we write e2e tests of a app having Next JS API in testcafe?

Our app is in React + NextJS. Framework is like (Browser code -> (Making call to)->Next JS Api->(Making call to)->External Rest API). I want to perform E2E Testing using Testcafe where I will mock only the External API call. How can we achieve the same?
Yes you can write E2E tests using testcafe. It simulates actual user experience and interact with your website. It is not dependent underlying tech stack. You just need to host your app and provide the url to testcafe config. Use regular css selectors to pick page elements and make assertions. You can also intercept API requests and use mock data for API. Mocking is not recommended for E2E testing.
Sample code for API response:
import { RequestLogger } from 'testcafe'
const logger= RequestLogger(['Domain URLs Array'], {
logResponseHeader: true,
logResponseBody: true
})
fixture(`description`).page('app url').requestHooks(logger)
test('description', async () => {
const domain1Res = logger.requests[0].response
const domain1ResStr = domain1Res.body.toString()
const domain1ResJson = domain1ResStr.length ? JSON.parse(domain1ResStr) : null
// domain1ResJson is the API response object, use it in assertions
})

How to run multiple tests under same fixture with same browser session

I am trying to test multiple features in one test.js file with each feature implemented as a test. All these tests can be run only after login to the portal. Testcafe closes the browser after the first test which fails the subsequent tests. I used Role and .beforeEach so that the tests can log in to the portal and proceed as usual but is there any easy way to just continue all the tests in the same browser session without really closing them after each test?
I used Role feature and .beforeEach which looks like a workaround to me. Is there any other way to run all tests one after another without really closing the browser session. This will save us the login operation and the instability that might cause for each test.
import { Selector , ClientFunction, Role } from 'testcafe';
import loginpage from '../../features/blah/login/page-model'
const appPortalUser2 = Role('https://test.com', async t => {
await loginpage.signInToPortal()
await loginpage.login('test-userm', 'Password123')
}, { preserveUrl: true });
fixture `portal - settings`
.page `https://test.com/apps`
.beforeEach (async t => {
await t`enter code here`
.useRole(appPortalUser2)
});
test('settings', async t => {
//test1
await loginpage.foo1()
});
test('backup', async t => {
//test2
await loginpage.foo2()
});
Actual behavior: after test1 browser exits and login page appears which fails test2 without using .beforeEach.
Expected: browser session should continue for test2 after test1 without .beforeEach. Provide such an option where tests can continue without creating new browser sessions each time.
At the moment, there is no such option in the public API.
The idea is that one test should not affect another test in any way. If all tests had run in one browser session, every test would have influenced all preceding tests as it could have had a page with an invalid state.

XMLHttpRequest is not defined when testing react-native app with jest

i am trying to test a apiwrapper in a react-native based app using jest (integration testing).
When i run it in the iOs simulator everything runs fine however it wont run my jest tests correctly - i always get:
ReferenceError: XMLHttpRequest is not defined
when i try to run tests using my api wrapper, eg.:
it('Login successful with correct data', () => {
let api = Api.getInstance();
return api.login("test", "testpass")
.then(result => expect(result).toEqual('login_successful'));
});
the api class i am trying to test here does use the fetch api (not vanilla xhr). I assume its something related to jest trying to mock something but have not found a way to make it work yet.
Thanks in advance.
In my case, I'm not testing the search code but only importing it somewhere in my code path, so I decided to just mock it at the global level in a setup.js file (loaded using --require at test run). The following works for me:
// needed in react-instantsearch
class XMLHttpRequest {}
global.XMLHttpRequest = XMLHttpRequest;
I had a similar problem with lokka using XMLHttpRequest. I made a mock for lokka, which my api wrapper class depends on. You could try mocking your api wrapper.
This is what my lokka mock looks like for now. I'll add more to it when I start testing error handling.
export default class {
query() {
return new Promise(resolve => {
resolve(200);
});
}
}
You might be able to mock your api wrapper with something similar:
export default class Api {
getInstance() {
\\ However you implemented getInstance
}
login(user, password) {
return new Promise(resolve => {
resolve('login_successful');
});
}
}