How can I use exported strings as my elements in Puppeteer - node.js

I can't seem to declare a string const and use that as my element with Puppeteer. For example:
await page.click("#playerView");
Works fine, but:
const playerViewId = "#playerView";
await page.click(playerViewId);
Doesn't. I ultimately want to hold all my Page Elements in an object in a separate file to tidy up my project.
Any ideas why this isn't working?
Thanks

I can confirm that the following case does in fact work:
const playerViewId = '#playerView';
await page.click(playerViewId);
If this is not working, consider upgrading your version of Node.js and/or Puppeteer.
If you are trying to define your variable in a separate file, you can use:
// external-file.js:
module.exports.playerViewId = '#playerView';
// main-file.js:
const external_variables = require('./external-file');
const playerViewId = external_variables.playerViewId;
await page.click(playerViewId);
Additionally, you should check to make sure that the element with id playerView exists and has loaded completely before attempting to use page.click().

Related

Node js - Issue with my syntax in require(module) . When to use {} and when not to use {} in require('module')

I have a query with the syntax in the require statement. Please refere the sample code below.
const nodemailer = require("nodemailer");
const {google} =require('googleapis');
const {OAuth2}=google.auth;
Some times , I see sample codes which use
const {<variable>} = require('moduleName')
Other times, I see like below
const <variable> = require('moduleName')
What is the difference between them?
Thanks in Advance.
Grateful to the Developers Community.
So, you use { } in this context when you want to do object destructuring to get a property from the exported object and create a module-level variable with that same name.
This:
const { google } = require('googleapis');
is a shortcut for this:
const __g = require('googleapis');
const google = __g.google;
So, within this context, you use the { google } only when you want the .google property from the imported module.
If you want the entire module handle such as this:
const nodemailer = require("nodemailer");
then, you don't use the { }. The only way to know which one you want for any given module is to consult the documentation for the module, the code for the module or examples of how to use the module. It depends entirely upon what the module exports and whether you want the top level export object or you want a property of that object.
It's important to realize that the { } used with require() is not special syntax associated with require(). This is normal object destructuring assignment, the same as if you did this:
// define some object
const x = { greeting: "hello" };
// use object destructuring assignment to create a new variable
// that contains the property of an existing object
const { greeting } = x;
console.log(greeting); // "hello
When you import the function with {}, it means you just import one function that available in the package. Maybe you have've seen:
const {googleApi, googleAir, googleWater} = require("googleapis")
But, when you not using {}, it means you import the whole package, just write:
const google = require("googleapis")
So, let say when you need googleApi in your code. You can call it:
google.googleApi

How to mock only one constant exported from a config file with many constants using Jest

I have a config file with simplified content (it contains several more constants) like this:
export const appTitle = "Drzewo wyboru"
export const warnings ={
missing:" Kryterium"
duplicate: "Duplikacja"
In a test file I have written a mock like this:
jest.mock('../../../src/config',()=>({AppTitle:'abc123test'}));
The problem is that other items in the config file are necessary to correctly render the tested component as well - so this mock breaks a test.
I have read about possible uses of jest.requireActual but it works with objects and in config I have loose items.
How could I mock only this one item, leaving the rest intact without changing the structure of my config file?
You can do partial mocking for your module:
jest.mock('../../../src/config',() => {
const originalModule = jest.requireActual('../../../src/config');
return {
__esModule: true,
...originalModule,
AppTitle: 'abc123test',
};
});
More information can be found in the official doc here.
(Your example states that you want to mock out AppTitle, yet the actual module contains appTitle which is a different property, I am not sure if this was a mistake, but if it was I can update my answer)

Require JSON as deep copy

I am writing tests right now for my node application.
I have fixtures which I use to test my data and I ran into the Problem, that when I alter any of them in a method, then they are globally altered for all the other tests as well, which obviously has to do with referencing. Now I figured if I write my fixtures into a JSON and require that JSON in each file then they will have unique references for each file, which turns out now, they don't.
My question would be: is there an easy way to handle fixtures in Node such that every file has an instance of the fixtures which won't affect the other test files.
The way I currently import my fixtures in every test file:
const {fixture1, someOtherFixture } = require('../../../../../fixtures/keywords.json');
require calls are cached, so once you call it, consecutive calls will return the same object.
You can do the following:
const {fixture1, someOtherFixture } = require('../../../../../fixtures/keywords.json');
const fixtureCopy = JSON.parse(JSON.stringify(fixture1));
const someOtherFixtureCopy = JSON.parse(JSON.stringify(someOtherFixtureCopy));
or use a package:
deepcopy
clone
const deepcopy = require('deepcopy');
const {fixture1, someOtherFixture } = require('../../../../../fixtures/keywords.json');
const fixtureCopy = deepcopy(fixture1);
const someOtherFixtureCopy = deepcopy(someOtherFixtureCopy);
Or change your module to export a function that will return new copies everytime. This is the recommended approach in my opinion.
module.exports = {
get() {
return deepcopy(fixture); // fixture being the Object you have
}
}
const fixture = require('./fixture');
const fixture1 = fixture.get();
This isn't specific to JSON. It's not uncommon that modules need to be re-evaluated in tests. require.cache can be modified in Node.js to affect how modules are cached, either directly or with helpers like decache.
Depending on the case,
decache('../../../../../fixtures/keywords.json')
goes before require in a test, or to afterEach to clean up.

Unable to use variables in fs functions when using brfs

I use browserify in order to be able to use require. To use fs functions with browserify i need to transform it with brfs but as far as I understood this results in only being able to input static strings as parameters inside my fs function. I want to be able to use variables for this.
I want to search for xml files in a specific directory and read them. Either by searching via text field or showing all of their data at once. In order to do this I need fs and browserify in order to require it.
const FS = require('fs')
function lookForRoom() {
let files = getFileNames()
findSearchedRoom(files)
}
function getFileNames() {
return FS.readdirSync('../data/')
}
function findSearchedRoom(files) {
const SEARCH_FIELD_ID = 'room'
let searchText = document.getElementById(SEARCH_FIELD_ID).value
files.forEach((file) => {
const SEARCHTEXT_FOUND = file.includes(searchText.toLowerCase())
if (SEARCHTEXT_FOUND) loadXML(file)
})
}
function loadXML(file) {
const XML2JS = require('xml2js')
let parser = new XML2JS.Parser()
let data = FS.readFile('../data/' + file)
console.dir(data);
}
module.exports = { lookForRoom: lookForRoom }
I want to be able to read contents out of a directory containing xml files.
Current status is that I can only do so when I provide a constant string to the fs function
The brfs README contains this gotcha:
Since brfs evaluates your source code statically, you can't use dynamic expressions that need to be evaluated at run time.
So, basically, you can't use brfs in the way you were hoping.
I want to be able to read contents out of a directory containing xml files
If by "a directory" you mean "any random directory, the name of which is determined by some form input", then that's not going to work. Browsers don't have direct access to directory contents, either locally or on a server.
You're not saying where that directory exists. If it's local (on the machine the browser is running on): I don't think there are standardized API's to do that, at all.
If it's on the server, then you need to implement an HTTP server that will accept a directory-/filename from some clientside code, and retrieve the file contents that way.

Can't get array of fs.Dirent from fs.readdir

I am using node 8.10.0.
fs.readdir() returns an array of filenames and child directory names, or fs.Dirents[].
I can't get that to work. Here's a simple example:
console.log(require("fs").readdirSync("/", {withFileTypes:true}));
This gives me an array of strings (e.g. ["bin", "mnt", "usr", "var", ...]), not an array of fs.Dirent objects (which is what I want).
How do I get this to work?
Required functionality is added in: v10.10.0, you have to update node.
I've hit the same problem and although I have the latest node.js (v10.16 currently) and intellisense in VS Code is consistent with the online documentation, the run-time reality surprised me. But that is because the code gets executed by node.js v10.2 (inside a VS Code extension).
So on node.js 10.2, this code works for me to get files in a directory:
import * as fs from 'fs';
import util = require('util');
export const readdir = util.promisify(fs.readdir);
let fileNames: string[] = await readdir(directory)
// keep only files, not directories
.filter(fileName => fs.statSync(path.join(directory, fileName)).isFile());
On the latest node.js, the same code could be simplified this way:
let fileEnts: fs.Dirent[] = await fs.promises.readdir(directory, { withFileTypes: true });
let fileNames: string[] = fileEnts
.filter(fileEnt => fileEnt.isFile())
.map(fileEnt => fileEnt.name);
The code snippets are in Typescript.

Resources