I am trying to add a pdf file to a dropzone in a Cypress test that Im creating
Ive added the cypress-upload-file package to help me do this.
In my commands.js file I have
Cypress.Commands.add("AddCandidate", function (candidate) {
cy.contains("Candidates").click()
cy.contains('Import Candidate').click()
cy.get('[id="resumeDz"]')
.attachFile({ './resumes': 'example.pdf', encoding: 'utf-8', subjectType: 'drag-n-drop' });})
and in my test I have
/// <reference types="cypress" />
describe('Add candidate', () => {
before(function () {
cy.visit(Cypress.env("home_page"));
cy.fixture('user').then(function (user) {
this.user = user
cy.SignIn({ email: (this.user.email), password: (this.user.password) })
})
})
it('Adds Candidate', function () {
cy.AddCandidate({})
})})
When running the test I get `"filePath" is not valid.
Please look into docs to find supported "filePath" values
Is there a specific way that i need to define the path ? Ive tried adding the full path, but Im still getting the same error. Is there something im missing ?`
SOLUTION
I ended up finding the solution.
Cypress.Commands.add("AddCandidate", function (candidate) {
cy.contains("Candidates").click()
cy.contains('Import Candidate').click()
cy.fixture('example.pdf', 'binary')
.then(Cypress.Blob.binaryStringToBlob)
.then(fileContent => {
cy.get('[type="file"]').attachFile({
fileContent,
filePath: 'example.pdf',
fileName: 'example.pdf',
});
cy.wait(1000)
cy.contains('Start').click()
cy.contains('Done').click()
});
})
The arguments to .attachFile() are a little messed up
cy.get('[id="resumeDz"]')
.attachFile('./resumes/example.pdf', {
encoding: 'utf-8',
subjectType: 'drag-n-drop'
});
presuming ./resumes/example.pdf is the path to the file relative to the fixtures folder.
With newer versions you can use the native cypress drag&drop action:
cy.get('#dropzone')
.selectFile('cypress/fixtures/file.txt', { action: 'drag-drop' });
Related
When I run the test, the specified URL does not open, even though it is entered correctly and set in BaseUrl in cypress.config.js:
> module.exports = defineConfig({ e2e: {
> "projectId": "fi4fhz",
> "viewportHeight": 1080,
> "viewportWidth": 1920,
> specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}',
> baseUrl: 'https://pha.mm.int:6001/',
>
> setupNodeEvents(on, config) {
>
> }, },
In every test file I have this:
beforeEach(() => {
cy.runInWeb();
});
and in commands.js I have:
Cypress.Commands.add("runInWeb", () => { cy.visit(Cypress.e2e().projectUrl) });
and in cypress.config.js I have:
"projectUrl": "https://pha.mm.int:6001/"
but it's not functioning. Where is the problem?
The baseUrl value https://pha.mm.int:6001/ shows up in the browser address bar because Cypress uses it to configure set up the runner.
But the <iframe> containing the web page under test isn't changed until you perform
the first cy.visit('/').
This is to allow you to execute code before the page load occurs, like cy.intercept() and cy.fixture().
Yes you visit() but not in the right way, if you store your url in env variable you get it out like this:
Cypress.Commands.add("runInWeb", () => { cy.visit(Cypress.env('projectUrl')) });
and you store the default like this:
// cypress.config.js
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
specPattern: 'cypress/e2e/**/*.cy.{js,jsx,ts,tsx}'
},
env: {
projectUrl: 'https://pha.mm.int:6001/',
},
})
or cypress.env.json
{
"projectUrl": "https://pha.mm.int:6001/"
}
Ensure that you have this beforeEach prior to running your it test blocks. You need to use cy.visit('/') before each of your tests.
beforeEach(() => {
//cy.session(id, setup); Use is if you want to stay logged into your application
cy.visit('/);
cy.wait(100);
});
If you're interested in using a session, visit the cypress docs here:
Based on the information in the question, I assume that you did not include a cy.visit() command. Without that command, Cypress does not know to open a webpage.
I have a problem with uploading a file from my pc via ngForm as part of a small project I do for a class. It seems that I cannot correctly upload the file as during debugging I get "fakedirectory/name-of-file" rather than the actual temp directory.
I did already search some related posts but they seem to be different than my case and I cannot get them to work.
I would greatly appreciate any help and guidance what can I try next.
I have a frontend part of the project and a separate rest api backend. I will paste the related code here:
HTML:
<form #addOfferForm="ngForm" (ngSubmit)="submitNewOffer(addOfferForm)">
Here I have other text inputs that work fine
...
<input (I tried with ngForm and without) type="file" accept="image/png" id="offerPhoto" (change)="handleOfferPhotoUpload($event)">
...
<button class="public">Publish</button>
Component:
offerPhoto?: File
handleOfferPhotoUpload(event: InputEvent){
const input: HTMLInputElement = event.target as HTMLInputElement;
this.offerPhoto = input.files[0]
console.log( "this.offerPhoto" + this.offerPhoto)
}
addOfferForm: FormGroup = new FormGroup({
offerName: new FormControl(''),
...
offerPhoto: new FormControl(''),
})
submitNewOffer(addOfferForm: NgForm): void {
this.offerService.addOffer$( addOfferForm.value).subscribe({
next: (offer) => {
this.router.navigate(['/offers'])
},
error: (error) => {
console.error(error)
}
})
Service:
addOffer$(body: { offerName: string, ... offerPhoto: File }): Observable<IOffer> //This is an interface that I use {
return this.http.post<IOffer>(`${apiUrl}/offers`, body, { withCredentials: true });
}
Then on the backend I have:
function createOffer(req, res, next) {
const { offerName, buyOrSell, cameraOrLens, offerDescription, offerPhoto, offerContact } = req.body;
const { _id: userId } = req.user;
uploadFile(offerPhoto).then(id => {
const offerPhoto = `https://drive.google.com/uc?id=${id}`
return offerModel.create({ offerName, ... offerPhoto, userId })
.then(offer => res.json(offer))
.catch(next);
})
The uploadFile function worked with a simpler form where I just update a photo that is already there but cannot seem to get the image uploaded as part of the form.
I am very stuck and don't know what else to try.
A very big thanks to anybody who can help me in advance!
I'm having an issue to test uploading a folder with files and subfolders. If I add folder structure to the fixture then cy.fixture() command doesn't recognize that is a directory that I want to upload but it looks inside the directory to find the files. I have tries also to use the cy.readFile() but I couldn't make it to work.
I have tried to create drag and drop command like this:
Cypress.Commands.add('dragAndDropFolder', (fileUrl, type = '') => {
return cy.readFile(fileUrl, 'binary')
.then(Cypress.Blob.binaryStringToArrayBuffer)
.then(blob => {
const nameSegments = fileUrl.split('/');
const name = nameSegments[nameSegments.length - 1];
const testFile = new File([blob], name, { type });
const event = {
dataTransfer: {
isDirectory: true,
isFile: false,
fullPath: `#${fileUrl}`,
files: [testFile],
items: [{ kind: 'file', type }],
types: ['Files'],
},
};
return cy
.get('[data-test-dropzone="true"]')
.first()
.trigger('dragenter', event)
.trigger('drop', event);
});
});
Another thing I have tried to use a our different functionality which is simple upload button and the attachFile() plugin:
cy.readFile('client/testfolder', 'binary').then(file => {
cy.get('#multiple_file_uploads_input').attachFile(file)
});
Drag and drop functionality is written in Elixir and this is how data transfer looks like:
{
isDirectory: true,
isFile: false,
fullPath: '#{path}',
createReader() {
return {
sentEntries: false,
readEntries(callback) {
if (!this.sentEntries) {
this.sentEntries = true;
callback([#{Enum.join(entries, ",")}]);
} else {
callback([]);
}
},
};
},
}
At least on Elixir side the fullPath: '#{path}', will be substituted by the real path like fullPath: '/some/path', so you need to remove hash (#) from your path at JavaScript side here fullPath: '#${fileUrl}',, probably could be just fullPath: fileUrl,
I have written some function in commands.js file for cypress automation testing, out of which I am able to invoke only one i.e."login" but unable to invoke other functions form another .js file. Cypress Test Runner showing
"TypeError: cy.FillAddCaseDetails is not a function"
describe('Adding a Case on CSS Poratal ', function() {
before(function () {
cy.login() // calling login function successfully
})
it('open add case',function(){
cy.wait(9000)
cy.hash().should('contains','#/home')
cy.wait(['#GETcontentLoad']);
cy.wait(['#POSTcontentLoad']);
cy.get('[uib-tooltip="Add Case"]').click({force:true})
cy.log('clicked on Add case')
cy.wait(3000)
cy.get('[ng-click="lookup.cancel()"]').click({force: true})
cy.get('[ng-click="lookup.closeAddCase()"]').click({force: true})
cy.get('[uib-tooltip="Add Case"]').click({force:true})
cy.wait(3000)
cy.get('[ng-model="lookup.selectedPartner"]',{force:true})
.type(AddJob.JobData.Partner,{force: true})
cy.xpath('//input[#ng-model="lookup.selectedPartner"]')
.should('be.visible').then(() => {
cy.FillAddCaseDetails() // unable to call
cy.FillCustomerDetails() // unable to call
})
Function:
Cypress.Commands.add("FillCustomerDetails", () => {
cy.get('[ng-model="lookup.firstName"]')
.type(AddJob.JobData.FirstName, { force: true})
cy.get('[ng-model="lookup.lastName"]')
.type(AddJob.JobData.LastName, { force: true })
cy.get('[ng-model="lookup.customerPhone"]')
.type(AddJob.JobData.CustomerPhone, { force: true })
cy.get('[value="NEXT"]').click({ force: true })
})
expected : function will get called
actual : TypeError: cy.FillAddCaseDetails is not a function
This is the top result for this error so I would like to add what I did to fix it. This is relevant to version >=10 and typescript. The problem ended up being that the supportFile setting in cypress.config.ts was set to false; I changed my config to this:
import cypress, { defineConfig } from 'cypress'
export default defineConfig({
e2e: {
'baseUrl': 'http://localhost:4200',
supportFile: 'cypress/support/e2e.ts'
},
})
I created the custom commands in commands.ts
declare namespace Cypress {
interface Chainable<Subject = any> {
/**
* Custom command to select DOM element by data-cy attribute.
* #example cy.dataCy('greeting')
*/
clearIndexedDB(): Promise<void>
}
}
Cypress.Commands.add('clearIndexedDB', async () => {
const databases = await window.indexedDB.databases();
await Promise.all(
databases.map(
({ name }) => {
if (!name) return
return new Promise((resolve, reject) => {
const request = window.indexedDB.deleteDatabase(name);
request.addEventListener('success', resolve);
request.addEventListener('blocked', resolve);
request.addEventListener('error', reject);
})
},
),
);
});
Then I uncommented this line in my e2e.ts file
import './commands';
In my case solution was a restart of the cypress test runner.
If you added your Custom Command to support/commands.js file, You need to import that file from support/index.js file. Create support/index.js, if it's not available and add the line import "./commands.js" to it.
From the Cypress docs: https://on.cypress.io/typescript#Types-for-custom-commands
if you add the command cy.dataCy into your supportFile like this:
// cypress/support/index.js
Cypress.Commands.add('dataCy', (value) => {
return cy.get(`[data-cy=${value}]`)
})
Then you can add the dataCy command to the global Cypress Chainable interface (so called because commands are chained together) by creating a new TypeScript definitions file beside your supportFile, in this case at cypress/support/index.d.ts.
// in cypress/support/index.d.ts
// load type definitions that come with Cypress module
/// <reference types="cypress" />
declare namespace Cypress {
interface Chainable {
/**
* Custom command to select DOM element by data-cy attribute.
* #example cy.dataCy('greeting')
*/
dataCy(value: string): Chainable<Element>
}
}
cy.xpath("//div[#class='c-navigatorItem-faceplate ng-scope ng-isolate-scope']").click();
Is it a valid to use because I am getting the TypeError cy.xpath is not a function
I'm making cordova ios application with meteor. And I'm using one custom made camera plugin. After recording a video I get only local path of that video. I have to make File object with that path. I tried new File('etc/path') but it doesn't work.
Edit:
I tried to make blob and make New File([blob], 'name), but that doesn't work either.
Thanks,
Igor
Thanks #Bertrand, you gave me an Idea how to fix the problem. I wrote this:
window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs){
fs.root.getFile('output.mov', { create: true, exclusive: false }, function (fileEntry) {
fileEntry.file(function (file){
console.log(file)
});
}, (err) => {
console.log(err)
});
}, (err) => {
console.log(err)
});