So I have major problem with importing from one class to another and what I have done is in my "main" class which I call
detailsPage.js
import { DetailsPage } from '../tests/detailsPageObj';
const utils = require("../utils/utils");
const assert = require('../node_modules/chai').assert;
const userData = require('../globalContent.json');
describe('Details page', function () {
const detailsPage = new DetailsPage();
// The details page is accessible by the specified URL
it(`Is defined by the URL: ${userData.url}`, async function () {
await detailsPage.navigate();
});
// Details page has a form and it can be filled out with user data
it('Has a form that can receive user data', async function () {
await detailsPage.fillFormWithUserData(); // If you want, make the user data passable to the method
await utils.click(detailsPage.form.buttons.nextStep);
});
if (detailsPage.hasStockConflict) {
// Details page allows the user to fix conflicts in stocks
it('Enables resolution of stock conflicts', async function () {
// Wait for stock to fully load
await browser.sleep(2000);
await detailsPage.clickAllRemoveButtons();
await detailsPage.clickAllDecreaseButtons();
});
}
// Details page allows the user to proceed to the next stage when all conflicts (if any) has been resolved
it('Allows the user to proceed to the next stage of purchasing', async function () {
const nextStepButton = detailsPage.form.buttons.nextStep;
await utils.elementToBeClickable(nextStepButton);
await utils.click(nextStepButton);
});
});
and what I am trying tod o is to get DetailsPage from another script which is called:
detailsPageObj
import { element, by } from 'protractor';
const utils = require("../utils/utils");
const userData = require('../globalContent.json');
export class DetailsPage {
get pageUtils() {
return {
qtyRegex: /^Sorry.*?(\d+)/
}
}
private get fields() {
return {
email: element(by.id('email')),
firstName: element(by.id('firstName')),
lastName: element(by.id('lastName')),
postalCode: element(by.id('postalCode')),
addressOne: element(by.id('addressOne')),
addressTwo: element(by.id('addressTwo')),
phone: element(by.id('phone')),
businessCustomerCB: element(by.id('isBusinessCustomer')),
company: element(by.id('company')),
GST: element(by.id('gst')),
}
}
private get groups() {
return {
address: element(by.css('div#addressGroup.input-container.showHiddenGroup'));
company: element(by.id('companyGroup')),
}
}
private get modals() {
return {
contactModalLink: element(by.id('contactModalLink')),
cross: element(by.className('modal-cross')),
}
}
private get formButtons() {
return {
nextStep: element(by.id('submitIdentityFormButton')),
mobile: this.mobileFormButtons
}
}
private get mobileFormButtons() {
return {
continue: element(by.id('stock-conflict-continue-button')),
removeOutOfStockItems: element(by.css('button[id="removeOutOfStockItems"]')), // I just assumed that this is a part of the form
}
}
private get productFrameMobileButtons() {
return {
stockControll: element.all(by.className('stock-controller mobile')),
remove: element.all(by.className('btn btn-remove btn-outlined mobile')),
}
}
private get productFrameDesktopButtons() {
return {
stockControll: element.all(by.className('stock-controller desktop')),
remove: element.all(by.className('btn btn-remove btn-outlined desktop')),
}
}
get form() {
return {
fields: this.fields,
groups: this.groups,
buttons: this.formButtons,
modals: this.modals
}
}
get productFrame() {
return {
buttons: {
decrease: element.all(by.className("btn left")).first(),
mobile: this.productFrameMobileButtons,
desktop: this.productFrameDesktopButtons
}
}
}
get errors() {
return {
stockConflict: element(by.className('generic-error-heading')),
}
}
}
and what I am trying to do is in detailsPage.js im trying to import detailsPageObj.js but whenever I am trying to do it I do get SyntaxError: Cannot use import statement outside a module.
What am I doing wrong
I don't know what is your environment like, but I experienced a similar problem where my environment used a full build step for creating the target JS code from my sources (e.g. from TypeScript or from ES6+) to a bundled/plain JS.
But then my test environment did not have any build step. So when I executed the tests, it only understood plain JS, which by default in a node.js environment does not recognize import but only require.
You can use import in your node.js code without a build step, but you need to follow some steps, e.g. rename your file from *.js to *.mjs. More details here.
Related
I am developping a JHipster blueprint and I need to use EJS to template the files I want to generate. Since this is my first time using EJS, all I am trying to do for now is use an answer from one of the generated question and create a java interface with its name.
This is the template I got:
public interface <%= databaseURL %> {
}
prompts.js:
function askForDatabaseURL(meta) {
const applicationType = this.applicationType;
const prompts = [
{
type: 'string',
name: 'databaseURL',
message:
'Quel est l\'URL de votre base de données ?',
default: 'URL'
}
];
if (meta) return PROMPTS;
const done = this.async();
this.prompt(prompts).then(prompt => {
this.log(this.databaseURL);
this.databaseURL = prompt.databaseURL;
this.log(this.databaseURL);
done();
});
}
module.exports = {
askForDatabaseURL
};
index.js:
const chalk = require('chalk');
const AppGenerator = require('generator-jhipster/generators/app');
const prompts = require('./prompts');
module.exports = class extends AppGenerator {
constructor(args, opts) {
super(args, { fromBlueprint: true, ...opts }); // fromBlueprint variable is important
this.databaseURL = "Hello";
}
get initializing() {
return super._initializing();
}
_prompting() {
return {
askForDatabaseURL: prompts.askForDatabaseURL
}
}
get prompting() {
const defaultPhaseFromJHipster = super._prompting();
const myPrompting = this._prompting();
return Object.assign(defaultPhaseFromJHipster, myPrompting);
}
get configuring() {
return super._configuring();
}
get default() {
return super._default();
}
_writing() {
this.fs.copyTpl(
this.templatePath(`src/main/java/package/repository/JOOQRepository.java.ejs`),
this.destinationPath(`${this.databaseURL}.java`),
{ databaseURL : this.databaseURL}
)
}
get writing() {
const defaultPhaseFromJHipster = super._writing();
const myWriting = this._writing()
return Object.assign(defaultPhaseFromJHipster, myWriting);
}
get install() {
return super._install();
}
get end() {
return super._end();
}
};
The problem is, after the prompting phase, this.databaseURL always has a value of "Hello" which is the default value in the constructor, meaning the file generated is always Hello.java.
I tried to add this.log(this.databaseURL); before and after this.databaseURL = prompt.databaseURL so I'd get an idea if this line does what it's supposed to and it does:
I am fairly new to JavaScript so I might have missed something very basic, but I don't understand why this.databaseURL returns "Hello" after assigning it the user's answer to it.
Any help is welcomed!
Through this article I learned that you can access these magic variables through JS as well (e.g. in HTML <div x-ref="navbarCollapse">...</div> and in JS this.$refs.navbarCollapse).
I was wondering whether that would work as well with the Persist plugin. The goal is to store a boolean whether the user accepted the Cookie Banner.
So I tried setting the variable as if it were placed in x-data, which looks like:
export default () => ({
open: this.$persist(false),
});
but that throws:
module.esm.js:1656 Alpine Expression Error: Illegal invocation
Expression: "open"
Next I tried placing in my init() function (which is async because I use GraphQL in there)
export default () => ({
open: false,
async init() {
this.open = this.$persist(false);
...
}
});
but then nothing happens.
For more context here is my currently working example with my own functions for reading/writing to local-storage.
import client from './graphql';
import {
gql,
} from '#apollo/client/core';
import {
storageGet,
storageHas,
storageSet,
} from './local-storage';
const COOKIE_CONSENT_NAME = 'cookieConsentAccepted';
export default () => ({
open: false,
enabled: false,
async init() {
// Get all relevant information from the API
const response = await client.query(
{
query: gql`
{
globalSets(handle: "globalsCookieBanner") {
... on globalsCookieBanner_GlobalSet {
cookieBannerStatus
}
}
}
`,
});
const data = response.data.globalSets[0];
this.enabled = data.cookieBannerStatus;
// Check whether to open cookie banner
if (this.enabled && (!storageHas(COOKIE_CONSENT_NAME) || (storageHas(COOKIE_CONSENT_NAME) && storageGet(COOKIE_CONSENT_NAME === false)))) {
this.open = true;
}
},
toggle() {
this.open = !this.open;
storageSet(COOKIE_CONSENT_NAME, !this.open);
},
});
I would like to put my calls to my API in a separate page and not in the template page of my app. So, I create a file "customersAPI.js" and I put this code :
export function findAllCustomers () {
axios.get('http://127.0.0.1:8000/api/customers')
.then((reponse)=>{
console.log(reponse.data['hydra:member'])
return reponse.data['hydra:member']
}).catch(err=>console.log(err))
}
So I try to retrieve my data in my template page and put these data in data but It does not work because of the asynchronous thing of api call and because I don't know how to pass the data...
I do this in my template page :
data() {
return {
customer: [],
}
},
mounted() {
this.getAllCustomers();
},
getAllCustomers() {
this.customer = findAllCustomers();
}
I know it is not the good way to do this but I don't know how to do... So I need clarification about that. And, every time I go into the documentation, there are no examples with an API call outside of the part where there is the page template. Is it a good practice to want to put the api call apart? And in general calls to functions so that the code is not too long?
Thanks for help
In your case I advise you to try add async in mounted or in func.
async mounted() {
this.customers = await this.findAllCustomers();
},
------
methods: {
async getAllCustomers(){
this.customer = await findAllCustomers();
}
}
But better practice to fetch information from store:
COMPONENT
<script>
import {mapActions} from 'vuex'
export default {
data() {
return {
customer: [],
}
},
mounted() {
this.customer = this.fetchAll();//better to get via getters
},
methods() {
...mapActions('customers', ['fetchAll']),
//OR
// fetchAllCustomers(){
// this.$store.dispath('customers/fetchAll')
// }
}
}
</script>
STORE
// async action that put all customers in store
const fetchAll = async ({ commit }) => {
commit(types.SET_ERROR, '')
commit(types.TOGGLE_LOADING, true)
try {
const { data} = await customerAPI.findAll(namespace)
commit(types.SET_ALLIDS, data['hydra:member'])
commit(types.TOGGLE_LOADING, false)
return data['hydra:member']
} catch (error) {
commit(types.TOGGLE_LOADING, false)
commit(types.SET_ERROR, error)
}
},
API
// func that receive promise
export function findAll () {
return axios.get('http://127.0.0.1:8000/api/customers')
}
Please read about vuex
https://vuex.vuejs.org/guide/actions.html
I'm trying follow the directions from the stripe elements docs and install the ES module into my Vue payment component.
Note, currently the Stripe websites ES module installation tab is down. Here's a substitute.
I ran:
npm install #stripe/stripe-js
Usage
import {loadStripe} from '#stripe/stripe-js';
const stripe = await loadStripe('pk_test_TYooMQauvdEDq54NiTphI7jx');
When I change my code to reflect the installation of the module I get this error:
30:17 error Parsing error: Can not use keyword 'await' outside an async function
import {loadStripe} from '#stripe/stripe-js';
let stripe = await loadStripe(`pk_test_mypin`)
elements = stripe.elements()
card = undefined;
export default {
mounted: function () {
card = elements.create('card', {
});
card.mount(this.$refs.card);
},
data () {
return {
cardHolderName: '',
stripeErrorMessage: null,
serverErrorMessage: null,
}
},
computed: {
},
methods: {
processPayment(){
let self = this;
stripe.createPaymentMethod(
'card', card, {
billing_details: { name: this.cardHolderName }
}).then(function(result) {
if(self.subscribitionCheckout){
self.submitPaymentForm(result.paymentMethod);
} else if (self.changePaymentMethod){
self.changePaymentMethod(result.paymentMethod)
}
if (result.error) {
self.stripeErrorMessage = result.error.message;
self.hasCardErrors = true;
self.$forceUpdate(); // Forcing the DOM to update so the Stripe Element can update.
return;
}
});
},
},
}
Before I had this
let stripe = Stripe(`pk_test_mypin`),
elements = stripe.elements(),
card = undefined;
Also, I based my code on this tutorial
First, put the expected top level vars in data:
stripe: {}, // or whatever data type
elements: {}, // or whatever data type
card: {}, // or whatever data type
Second, make a created lifecycle hook and load the content there:
created()
{
loadStripe(`pk_test_TYooMQauvdEDq54NiTphI7jx`).
then ( (result) =>
{
this.elements = result.elements
// do stuff with card if you have too...
},
},
I'm having a difficult time trying to test a methods in meteor that requires a connected user. Basically I need to test if a user of the app can add an article to it's cart. The methods will tests if a user is connected and, in order to test that will use Meteor.userId(). This seems to be a problem in unit testing as I get the error:
"Meteor.userId can only be invoked in method calls or publications."
So far, I tried to do what's proposed in this post: How to unit test a meteor method with practicalmeteor:mocha but I don't understand what the solution is doing.
Here is my testing method:
import { Meteor } from 'meteor/meteor';
import { Random } from 'meteor/random';
import { assert } from 'meteor/practicalmeteor:chai';
import { sinon } from 'meteor/practicalmeteor:sinon';
import { Carts } from '/imports/api/carts/carts.js';
import { Articles } from '/imports/api/articles/articles.js';
import '/imports/api/carts/carts.methods.js';
import { SecurityEnsurer } from '/lib/security/security.js';
function randomInt (low, high) {
return Math.floor(Math.random() * (high - low) + low);
}
if (Meteor.isServer) {
describe('Carts', () => {
describe('methods', () => {
let currentUser;
beforeEach(() => {
Factory.define('user', Meteor.users, {
name: "userTest",
currentUser: {
email: 'user#shop.info',
password: '123456',
}
});
currentUser = Factory.create('user');
sinon.stub(Meteor, 'user');
Meteor.user.returns(currentUser);
Articles.remove({});
articleId = Articles.insert({
name : "azerty",
description : "descTest",
modelNumber : "wxcvbn",
categoryName : "CatTest",
price : 1,
advisedPrice: 2,
supplierDiscount : 0,
brandId : "BrandTest",
isAvailable: true,
restockingTime: 42,
color: "Yellow",
technicals: [
{
name : "GPU",
value : "Intel"
},
],
});
Carts.insert({
owner: currentUser,
entries: [],
});
});
afterEach(() => {
Meteor.user.restore();
Articles.remove({});
Carts.remove({});
});
it('can add article', () => {
let quantity = randomInt(1,50);
const addArticleToCart = Meteor.server.method_handlers['carts.addArticle'];
const invocation = {};
addArticleToCart.apply(invocation, [articleId, quantity]);
assert.equal(Cart.find({owner: currentUser, entries: {$elemMatch: {articleId, quantity}}}).count(), 1);
});
});
});
}
If anyone can help me find out how to create my test, this would realy help me.
To fake a user when calling a Meteor Method, the only way I found is to use the mdg:validated-method package which provide a framework around Meteor methods. This framework seems to be the standard now (see the Meteor guide), but it requires to re-write your methods and the in-app calls.
After describing the methods using this framework, you are able to call them with the userId parameter when testing, using this kind of code (which verifies that my method is returning a 403 error):
assert.throws(function () {
updateData._execute({userId: myExternalUserId}, {
id: dataId,
data: {name: "test"}
});
}, Meteor.Error, /403/);
FYI, here are the packages I add when I do automated testing (Meteor 1.6 used):
meteortesting:mocha
dburles:factory
practicalmeteor:chai
johanbrook:publication-collector
Here's how I set up a fake logged in user for testing publish and methods:
1) create a user
2) stub i.e. replace the Meteor.user() and Meteor.userId() functions which return the current logged in user in methods
3) provide that user's _id to PublicationsCollector, which will send it in to your publish function.
Here's how I did it, I hope you can adapt from this:
import { Meteor } from 'meteor/meteor';
import { Factory } from 'meteor/dburles:factory';
import { PublicationCollector } from 'meteor/johanbrook:publication-collector';
import { resetDatabase } from 'meteor/xolvio:cleaner';
import faker from 'faker';
import { Random } from 'meteor/random';
import { chai, assert } from 'meteor/practicalmeteor:chai';
import sinon from 'sinon';
// and also import your publish and collection
Factory.define('user', Meteor.users, {
'name': 'Josephine',
});
if (Meteor.isServer) {
describe('Menus', () => {
beforeEach(function () {
resetDatabase();
const currentUser = Factory.create('user');
sinon.stub(Meteor, 'user');
Meteor.user.returns(currentUser); // now Meteor.user() will return the user we just created
sinon.stub(Meteor, 'userId');
Meteor.userId.returns(currentUser._id); // needed in methods
// and create a Menu object in the Menus collection
});
afterEach(() => {
Meteor.user.restore();
resetDatabase();
});
describe('publish', () => {
it('can view menus', (done) => {
const collector = new PublicationCollector({ 'userId': Meteor.user()._id }); // give publish a value for this.userId
collector.collect(
'menus',
(collections) => {
assert.equal(collections.menus.length, 1);
done();
},
);
});
});
});
}
You can also write a test for calling a Meteor method that relies on Meteor.userId():
expect(() => { Meteor.call('myMethod'); }).to.not.throw(Meteor.Error);