Maybe i asked wrong question.
i'm trying to test some site, and have this throw in terminal
terminal output
it's obvious, that function returns uuid after it was called in code.
it work's normaly, when i take element right in code, so the reason, i think, in uncorrect import
here's my code :
file.js
describe('final homeTask', () => {
it('firstassigment', async () => {
let mainPage = require('../page/main.pageHW.js')
await browser.url('https://github.com/')
let signUpButton = await mainPage.topSignUpBtn()
await signUpButton.click()
})
})
main.pageHW.js
class MainPage {
get topSignUpBtn () { return $('a.btn-mktg:nth-child(1)') }
}
module.exports = new MainPage()
It is a problem with Javascript, not about webdriver, you are using a property in the MainPage class:
class MainPage {
/// The get word make it a property
get topSignUpBtn () { return $('a.btn-mktg:nth-child(1)') }
}
module.exports = new MainPage()
That means you DON'T need parentheses to use it, so, replace:
let signUpButton = await mainPage.topSignUpBtn()
By
let signUpButton = await mainPage.topSignUpBtn;
Also, the property doesn't need the await clause.
If you want more info you can check this link.
Related
So, I searched for an existing solution, but I could find nothing, or maybe I'm not searching the correct way, thus, sorry if there's an existing thread about it.
In sum, it seems my code is not instantiating an object correctly as a class when it comes from an Axios call to the backend. So, when I call some function, I'm getting the error Uncaught TypeError TypeError: object.method is not a function.
Example:
First, basically, a parent component will call a service that will make a request to the backend. The result is then passed to a child component.
// imports
const Component: React.FC<ComponentProps> = () => {
const { id } = useParams<{ id: string }>();
const [object, setObject] = useState<Class>(new Class());
useEffect(() => {
(async () => {
try {
const object = await Service.getById(id);
setObject(object);
} catch (err) {
//error handling
} finally {
cleanup();
}
})();
return () => {
// cleanup
};
});
return (
<Container title={object.name}>
<Child object={object} />
</Container>
);
};
export default Component;
Then, in child component, let's say I try to call a method that was defined in the Class, there I'm getting the not a function error:
// imports
interface Interface {
object: Class;
}
const Child: React.FC<Interface> = ({ object }) => {
object.callSomeFunction(); // error starts here
return (
<SomeJSXCode />
);
};
export default Child;
Example of the Class code, I tried to write the method as a function, arrow function, and a getter, but none worked. Also, as a workaround, I've been defining a method to instantiate the object and set all properties, but I don't think that's a good long-term solution, and for classes with many properties, it gets huge:
export class Class {
id: string = '';
name: string = '';
callSomeFunction = () => {
// do something;
}
static from(object: Class): Class {
const newInstance = new Class();
newInstance.id = object.id;
newInstance.name = object.name;
// imagine doing this for a class with many attributes
return newInstance;
}
}
Finally, the Service code if necessary to better understand:
// imports
const URL = 'http://localhost:8000';
const baseConfig: AxiosRequestConfig = {
baseURL: URL,
headers: { 'Content-Type': 'application/json' },
withCredentials: true,
};
export const backend = axios.create({
...baseConfig,
baseURL: URL + '/someEndpoint',
});
export const Service = {
async getById(id: string): Promise<Class> {
try {
const { data } = await backend.get<Class>(`/${id}`);
return data;
} catch (err) {
throw new Error(err.response.data.message);
}
},
};
As I can't share the real code due to privacy, please let me know if this is enough or if more information is needed. Thanks in advance.
I thought it was some binding issue as here, but no.
So, I actually fixed this by updating the class validator in the back end, as the parsing was only necessary to parse the strings as number. But, by adding the annotation #Type(() => Number) to my dtos, I won't need to parse the strings anymore.
I have a aws lambda written in JS (TypeScript) which calls functions from different classes. I am getting undefined for the existingproducts variable even though it works fine when the REACT UI sends a call to the function. Below is my code using this keyword to reference the method of other class with current object in scope.
Entry point for the lambda
export const handler = async (upload: FileUpload, context: Context) => {
.....code .....
const parser = new ExcelValidator(new LookupService(), new ProductService());
const status = await parser.performExistingUpcValidation(products as Product[], upload, workbook);
return status
PerformExisitingUPCValidation
export class ExcelValidator {
constructor(public lookupService: LookupService, public productService: ProductService) {
}
async performExistingUpcValidation(products: Product[], upload: FileUpload, workbook?: Workbook): Promise<FileStatus> {
...code...
const existingProducts: any[] = await this.productService.getExistingProductsByUpcOrProductCode(productUpcs, productCodes);
console.log("This is the exisitingProduct", existingProducts)
}
ProductServiceClass
export class ProductService {
constructor() {
}
#Query(()=>[Product])
async getExistingProductsByUpcOrProductCode(#Arg("upcs", ()=> [String]) upcs: string[], #Arg("productCodes", ()=> [String]) productCodes: string[]): Promise<Product[]> {
console.log("I came here")
let query = `SELECT * from table
in (${upcs.join(",")})`;
if(productCodes.length){
query += ` OR "productCode" in ('${productCodes.join("','")}')`;
}
const results = await pool.snowflake?.execute(query);
return results as Product[];
}
After all the execution I am able to see
This is the exisitingProduct undefined
which means my execution does not reach the ProductServiceClass. Can someone point me to what is wrong or missing? Also any documentation/reference to read more will help alot.
My suggestion for you is review the item below:
const results = await pool.snowflake?.execute(query);
Are you confident that snowflake is not null, because you are accepting to be undefined with help of the question mark.
Below is the code for the test file
const { test, expect } = require('#playwright/test')
const HomePage = require('./pageobejcts/HomePage')
test.beforeEach(async ({ page }) => {
await page.goto("https://automationexercise.com/");
})
test('Navigate to Login', async ({ page }) => {
let homepage = new HomePage(page);
homepage.navigateToLoginSignUp();
await expect(page.locator('//div[#class="signup-form"]/h2')).toBeVisible();
await page.screenshot({ path: 'screenshot.png' });
//await expect(page.locator('//img[#alt="Website for automation practice"]')).toBeVisible;
})
And below is code for one of the Screen class
class HomePage {
constructor(page) {
this.page = page;
this.signupLnk = '//a[#href="/login"]';
}
async clickSignupLink() {
await this.page.click(this.signupLnk);
}
}
module.exports = HomePage;
Now the above code works fine. But in the Screen Class, as there is no Page object defined, there is no auto-complete/documentation available when using the Page methods.
eg On writing page.click(), the IDE does not recognize the click function and does not suggest the correct parameters
Is there a way to resolve this?
If I understand Your question correctly this should work:
let homepage = new HomePage(page);
await homepage.page.click('selector')
Also I suggest to use Fixtures in combination with page object model.
await this.signupLnk.click();
You can call the locator directly and call the click function on it.
add this to class file -
/**
#param {import('#playwright/test').Page} page
*/
Probably this is a very stupid question, i'm new in Node.js and javascript, so please forgive me if the question is not properly explained or the answer is simple...
I'm trying to send 2 variables thru a url... When i send only 1 variable (artist=${term}) work all good, but I'm really stuck with about how to send 2 variables thru the url (&artist=${term1}&album=${term2})
I've work on this code so far which for 1 variable is working well... but i have no idea how to add a second or a third variable to the request:
File 1: "./services/albumInfo.js"
import { BRV_API } from '../../config';
import axios from 'axios';
import dotenv from 'dotenv';
const ALBUM_INFO = 'method=album.getinfo';
dotenv.config();
const doRequest = async (url) => {
return await axios.get(`${BRV_API}/${url}&api_key=${process.env.API_KEY}&format=json`);
};
export const infoAlbum = async (term) => {
return await doRequest(`?${ALBUM_INFO}&artist=${term}`);
};
File 2: "./repositories/albumInfo.js"
import { infoAlbum } from '../repositories/albumInfo';
import status from 'http-status';
export const albumInfo = async (req, res, next) => {
try {
const { query } = req;
const { data } = await infoAlbum(query.name);
const response = data;
res.status(status.OK).send(response);
} catch (error) {
next(error);
}
};
I know that my problem is in this part of the code (I guess)
export const infoAlbum = async (term) => {
return await doRequest(`?${ALBUM_INFO}&artist=${term1}&album=${term2}`);
};
I've been searching, and i've seen some solution, like this one, but i just don't understand those solutions or how to apply on my code (sorry for that, im a very new on this)
Any good soul who can help this newbie? (if can explain the why of the solution as well, for understand, will be amazing!!)
Thanks in advance!!
Axios provides parameters that can be added custom as the following
const your_url = process.env.URL
const infoAlbum = await axios.get(your_url,{
params: {
artist: term,
album: term2,
api_key: process.env.API_KEY,
format:'json'
}
})
console.log(infoAlbum.data.args)
note: your_url without any more parameters.
So,
I've found a solution, which is pretty ugly, but so far is working, if someone have a better option, will be amazing to know:
File 1: repositories/albumInfo.js, I've just add the console (as per #Alex028502 suggestion), to know what the code was returning:
import { BRV_API } from '../../config';
import axios from 'axios';
import dotenv from 'dotenv';
const ALBUM_INFO = 'method=album.getinfo';
dotenv.config();
const doRequest = async (url) => {
const fullurl = `${BRV_API}/?${ALBUM_INFO}${url}&api_key=${process.env.API_KEY}&format=json`;
console.log('full url is', fullurl);
return await axios.get(fullurl);
};
export const infoAlbum = async (term) => {
return await doRequest(`&${term}`);
};
File 1: services/albumInfo.js: I change the behaviour of 'infoAlbum' to make the request from his side:
import { infoAlbum } from '../repositories/albumInfo';
import status from 'http-status';
export const albumInfo = async (req, res, next) => {
try {
const { query } = req;
console.log(query);
const { data } = await infoAlbum('artist=' + query.artist + '&album=' + query.album);
const response = data;
res.status(status.OK).send(response);
} catch (error) {
next(error);
}
};
I know that probably this is not the very best way to walk away from the problem, but so far is what i have.... any other better option about how to capture the second or third parameter of the url request and then add them to the final url?
Best!
I have a couple questions regarding Class files. I have the below Class
class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
my problem is how can I go and access the doSomeQuery function from outside the class file? Inside there is no issue accessing the function but I need to be able to call it from outside.
I tried something like this
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
doing so newTest never exposes the doSomeQuery method.
Also what are the limitations of a method ? Can it only be a simple one or can it be async and use promises etc ?
There are 2 main things that you should consider with the following problem.
Export it properly first. I'm not sure if you meant to leave this out, but it's important to export the class for use outside as a require. Here is the NodeJS exports documentation if you wish for the technical details.
// common module default export
module.exports = class CouchController {
constructor(couchbase, config) {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
doSomeQuery(queryString, callback) {
this.bucket.manager().createPrimaryIndex(function() {
this.bucket.query(
this.N1qlQuery.fromString("SELECT * FROM bucketname WHERE $1 in interests LIMIT 1"),
[queryString],
callback(err, result)
)
});
}
}
The class initialization is slightly incorrect. You can see the docs on this here. You can change your require and initialization to...
const CouchController = require('../controllers/CouchController');
const newTest = new CouchController(couchbase, config);
// now you can access the function :)
newTest.doSomeQuery("query it up", () => {
// here is your callback
})
If you were using ES6 modules or typescript you could export something like...
export default class CouchController {
// ...
}
... and import something like...
import CouchController from '../controllers/CouchController';
const newTest = new CouchController(couchbase, config);
You need to instantiate the class after importing it
Change the following
const CouchController = require("../controllers/CouchController")(couchbase, config)
let newTest = new CouchController
to
const CouchController = require("../controllers/CouchController")
let newTest = new CouchController(couchbase, config)
Also you need to export your class like this
export default class CouchController {
and then access method like this
newTest.doSomeQuery(...)
I figured it out after some forth and back, part of my problem was the fact that for some reason visual studio code did not show me the method which threw me off. Manually typing made it ultimately avail.
Here is my Class and i actually moved the config and couchbase itself into the class file so no need to pass it anymore.
const couchbase = require("couchbase")
const config = require("../config/config")
class CouchController {
constructor() {
// You may either pass couchbase and config as params, or import directly into the controller
this.cluster = new couchbase.Cluster(config.cluster);
this.cluster.authenticate(config.userid, config.password);
this.bucket = this.cluster.openBucket(config.bucket);
this.N1qlQuery = couchbase.N1qlQuery;
}
getDoc2(docID){
return new Promise((resolve,reject)=>{
this.bucket.get(docID ,(err, result)=>{
if(err) return reject(err);
return resolve({docID,result});
});
});
}
}
module.exports = CouchController
And here is how i call my Class now and connect to the backend to fetch my data.
const CouchController = require("./controllers/CouchController")
let newTest = new CouchController
const test= async()=>{
let { docID, result } = await newTest.getDoc2("grid_info::20b05192-79e9-4e9d-94c9-91a4fc0a2765")
console.log(docID)
console.log(result)
}