I am trying to declare a ClientFunction on a Factory page and then call it on a test page. But I am doing something wrong and it doesn’t work. I have two pages one is factory page, second test page.
In test page i have ClientFunction and it works fine. When i trying move to Factory Page it doesn't working.
import {Selector, ClientFunction} from "testcafe";
import videoPage from "../pages/video_player_page";
const videoElement = Selector("#bod-video-player_html5_api");
const currentTime = ClientFunction(() => {
return videoElement().currentTime;
}, {dependencies: {videoElement}});
test
.page(`some video page url`)
("Verify video functionality in LO State ", async (t) => {
let m1 = currentTime();
console.log("m1 = " + m1);
await t
.click(videoPage.fwdButton)
.expect(videoPage.videoPlayer.hasClass("vjs-seeking")).notOk();
let m2 = currentTime();
console.log("m2 = " + m2);
await t.expect(m2).gt(m1+25, "fwd button not working");
});
in factory page i have
import {Selector, t, ClientFunction} from "testcafe";
import {selectors} from "../constants/video_player_page_constants";
import {errorMessages} from "../constants/error_messages/video_player_page_messages";
class VideoPlayerPage {
constructor() {
this.skipAd = Selector(`${selectors.skipAdLocator}`, {timeout: 50000});
this.waiverModal = Selector(`${selectors.warningModalInVideoLocator}`);
this.videoPlayer = Selector(`${selectors.videoPlayerLocator}`);
this.videoPlaying = selectors.videoPlaying;
this.videoPaused = selectors.videoPaused;
this.waiverModalCheckbox = Selector(`${selectors.warningModalCheckbox}`);
this.waiverModalCheckboxCss = selectors.warningModalCheckbox;
this.acceptButton = Selector(`${selectors.warningModalAcceptButton}`);
this.playPauseButton = Selector(`${selectors.playPauseButtonLocator}`);
this.fwdButton = Selector(`${selectors.fwdButtonLocator}`);
this.bwdButton = Selector(`${selectors.bwdButtonLocator}`);
this.videoElement = Selector("#bod-video-player_html5_api");
}
async acceptWaiver() {
await t
.expect(this.waiverModal.exists).ok(errorMessages.warningModalNotExist)
.hover(this.waiverModalCheckboxCss)
.click(this.waiverModalCheckbox)
.click(this.acceptButton);
}
async skipAdd() {
if (await this.skipAd.visible) {
await t.click(this.skipAd);
}
}
} export default new VideoPlayerPage();
How to declare a ClientFunction on the Factory page, thanks for the help.
You can do this:
import { ClientFunction } from 'testcafe';
class VideoPlayerPage {
currentTime () {
return ClientFunction(() => {
const videoEl = document.querySelector('#bod-video-player_html5_api');
return videoEl.currentTime;
})();
}
}
When I trying move to Factory Page it doesn't work.
I guess that's because you export only an instance of VideoPlayerPage, so if you just copy & paster your ClientFunction code, than it's not exported in the first place, so you can't use it in your test file.
EDIT:
If you want to send a selector to ClientFunction as a parameter, this is the way to do it:
import { ClientFunction } from 'testcafe';
class VideoPlayerPage {
constructor () {
this.videoSelector = '#bod-video-player_html5_api';
}
currentTime () {
return ClientFunction(selector => {
const videoEl = document.querySelector(selector);
return videoEl.currentTime;
})(this.videoSelector);
}
}
Related
I was trying to load CoinbaseWalletSDK in my NextJS application, but it always throw an error of ReferenceError: localStorage is not defined due to it was imported before the window is loaded. I tried dynamic loading but it doesn't work. The following is what I am using at this moment.
export async function getServerSideProps({
params,
}: {
params: { project_id: string };
}) {
const project_id = params.project_id;
let project: any = fakeProjects[0];
if (project_id && typeof project_id === 'string' && !isNaN(parseInt(project_id))) {
const id = project_id;
project = fakeProjects.find(p => p.id === parseInt(id));
// Fetch project detail here
let item = await (
getNFTStatsByProjectId(
parseInt(project_id)
)
);
if (project && item && item['nftTotal'] && item['nftSold']) {
if (item.nftSold > item.nftTotal) {
item.nftSold = item.nftTotal;
}
project.nftTotal = item.nftTotal;
project.nftSold = item.nftSold;
}
}
const { coinbaseEth } = (await import('../../components/services/coinbase'));
return {
props: {
project: project,
coinbaseEth: coinbaseEth
},
};
}
And this is what I have in the coinbase service:
// TypeScript
import CoinbaseWalletSDK from '#coinbase/wallet-sdk'
import Web3 from 'web3'
const APP_NAME = 'Practice App'
const APP_LOGO_URL = process.env.WEBSITE_URL + '/logo.png'
const DEFAULT_ETH_JSONRPC_URL = 'https://mainnet.infura.io/v3/' + process.env.INFURA_PROJECT_ID
const DEFAULT_CHAIN_ID = 1
// Initialize Coinbase Wallet SDK
export const coinbaseWallet = new CoinbaseWalletSDK({
appName: APP_NAME,
appLogoUrl: APP_LOGO_URL,
darkMode: false
})
// Initialize a Web3 Provider object
export const coinbaseEth = coinbaseWallet.makeWeb3Provider(DEFAULT_ETH_JSONRPC_URL, DEFAULT_CHAIN_ID)
// Initialize a Web3 object
export const web3 = new Web3(coinbaseEth as any)
The new CoinbaseWalletSDK is where the error was thrown if that's a concern.
Based on my research, I will need to get it imported after the page is fully loaded (which is the point when "window" become available, as well as "localStorage"), which I have no clue how to achieve. Can anyone help me out on this?
I solved it by loading it later. What I did was to assign this variable with this function.
setTimeout(async () => {
coinbaseEth = (await import('../../components/services/coinbase')).coinbaseEth;
}, 1000)
I choose not to use useEffect because the value will be lost on render, which prevents the function to work properly.
I am playing with a client side router code from https://github.com/dcode-youtube/single-page-app-vanilla-js repo. I try to change this code in a way that i can reuse, because in the original code he hardcoded the routes in the router function.
I know(i think i know) the main reason why i get the unexpected reserved word error, i just dont know how to solve it.
Router.js
export default class trdsRouter{
constructor(routes){
this.routes = routes;
window.addEventListener("popstate", this.run);
document.body.addEventListener("click", e => {
if (e.target.matches("[trds-router-link]")) {
e.preventDefault();
this.navigateTo(e.target.href);
}
});
}
run = () => {
const potentialMatches = this.routes.map(route => {
return {
route: route,
result: location.pathname.match(pathToRegex(route.path))
};
});
let match = potentialMatches.find(potentialMatch => potentialMatch.result !== null);
if (!match) {
match = {
route: this.routes[0],
result: [location.pathname]
}
}
// THIS LINE IS THE PROBLEM
const view = new match.route.view(getParams(match));
document.querySelector("#app").innerHTML = await view.getHtml();
}
navigateTo = url => {
history.pushState(null, null, url);
this.run();
}
}
const pathToRegex = path => new RegExp("^" + path.replace(/\//g, "\\/").replace(/:\w+/g, "(.+)") + "$");
const getParams = match => {
const values = match.result.slice(1);
const keys = Array.from(match.route.path.matchAll(/:(\w+)/g)).map(result => result[1]);
return Object.fromEntries(keys.map((key, i) => {
return [key, values[i]];
}));
};
where i construct the router:
import trdsRouter from "./router.js";
import Dashboard from "./views/Dashboard.js";
import Posts from "./views/Posts.js";
import PostView from "./views/PostView.js";
import Settings from "./views/Settings.js";
let router = new trdsRouter([
{ path: "/", view: Dashboard },
{ path: "/posts", view: Posts },
{ path: "/posts/:id", view: PostView },
{ path: "/settings", view: Settings }
]);
router.run();
And then there is the abstract view class(i extend this class for the dashboard, posts, etc.):
export default class {
constructor(params) {
this.params = params;
}
setTitle(title) {
document.title = title;
}
async getHtml() {
return "";
}
}
So i think the problem is that in the trdsRouter class it does not yet know that a routes view property is a class( but i pass a class to it when i construct the router), thats why it throws error. how would i solve this? thank you.
Im sorry guys, it was a terrible mistake. The problem wasnt the new keyword highlighted in the routers code but the next line with the 'await' keyword. The routers run function wasnt declared as async so it threw the error. Changed the run function to async and it works. Thank you for your comments.
I am trying to implement a singleton pattern for the fastify instance. My code is as follows :-
const { createFastifyServer: server } = require("../app");
const getFastifyInstance = (() => {
let fastify;
return {
fastifyInstance: async () => {
if (!fastify) {
console.log("Called")
fastify = server();
await fastify.ready();
}
return fastify
}
}
})();
const { fastifyInstance } = getFastifyInstance
module.exports = fastifyInstance
Now wherever I am importing the code in a different file, the console prints "Called" each time it's imported in a new file, but shouldn't that be only once if singleton pattern was correctly implemented. Any idea what am I doing wrong?
I want to test function which manipulate my DOM. Thus I use jsdom + jest.
If I import the function, then the DOM loads not correctly and I receive a TypeError. The Error tells my that an element is not defined. Which would be defined in the beginning of my main.js.
If I don't import the function, then I could not run the test, because the function is not defined.
the test.js:
const { JSDOM,VirtualConsole} = require('jsdom')
//the function i want to import
const round = require("./main.js").round;
describe('calculate', () => {
let dom
let document
//load the DOM before all tests
beforeAll(async () => {
dom = await initDom('index.html')
document = dom.window.document
})
//my test to test the "round"-function
test(`round`, () => {
expect(round(0.12345)).toEqual(0.12)
})
})
important part of main.js:
module.exports = {
round: round,
}
const pongbar_right = document.getElementById("pongbar_right");
pongbar_right.style.top = 250;
-> here is be the Error: TypeError: Cannot read property 'style' of null
initDom:
const {JSDOM, VirtualConsole} = require('jsdom')
global.initDom = (htmlFile) => {
const virtualConsole = new VirtualConsole();
virtualConsole.on('log', (...args) => {console.log(`&${args}`)})
return JSDOM.fromFile(htmlFile, {
resources: 'usable',
runScripts: "outside-only",
virtualConsole
})
}
I have a lot of middleware. Here is one of them. How can I test my middleware with type compliance and with context.state validation on typescript ?
async function internationalizationPlugin(
context: ParameterizedContext<AppState, AppContext>,
next: Next
) {
context.state.i18n = await (i18next as any).createInstance({
lng: context.state.language,
fallbackLng: 'en',
})
await next()
}
a linter will check for type compliances and will be able to customize them more. However, you would just need to make sure that you export the function to your test file and then run a expect(typeof context).to.be(ParameterizedContext<AppState, AppContext>) that's not 100% copy/pasteable code, but, I think that it is on the right track. Also, for testability it could be easier if you created a class out of your middlewares that way importing and testing are done easier.
It's my simple type support solution. I'm not sure if it is suitable for everyone.
import * as httpMocks from 'node-mocks-http'
import * as Koa from 'koa'
export interface MockContext<RequestBody = undefined> extends Koa.Context {
request: Koa.Context['request'] & {
body?: RequestBody
}
}
export const koaMockContext = <
State = Koa.DefaultState,
Context = MockContext,
RequestBody = undefined
>(
requestBody?: RequestBody
) => {
const req = httpMocks.createRequest()
const res = httpMocks.createResponse()
const app = new Koa<State, Context>()
const context = app.createContext(req, res) as MockContext<RequestBody> & Koa.ParameterizedContext<State, Context>
res.statusCode = 404
context.request.body = requestBody
return context
}
And example
import { AppContext, AppState } from './types'
import { koaMockContext } from './utils'
import { internationalizationPlugin } from '../src/internationalizationPlugin'
describe('internationalizationPlugin', () => {
const ctx = koaMockContext<AppState, AppContext>()
it('should not be undefined', async () => {
await internationalizationPlugin(ctx, async () => {})
expect(ctx.state.i18n).not.toBe(undefined)
})
})