I use ssh command in cypress exec command. ssh command works properly but I get timeout error from exec() function always.
My code is :
cy.exec('ssh username#111.111.1.1 "\file.exe"')
Actually this code works properly and I can see that file.exe works on remote desktop but I get error on exec().
I think I have to put some options inside the ssh command like -q -w . I tried some of them but it did not work.
Could you please help me?
Maybe exec is too limited in the way you can interact with the command being called, you need a programmable API rather than just configuration options.
You can try using a task instead, there is a library node-ssh that will interface with a Cypress task.
I'm not familiar with ssh protocols, so you will have to fill in those details, but here is a basic example for Cypress task and the node-ssh library
cypress/plugins/index.js
module.exports = (on, config) => {
on('task', {
ssh(params) {
const {username, host, remoteCommand} = params // destructure the argument
const {NodeSSH} = require('node-ssh')
const ssh = new NodeSSH()
ssh.connect({
host: host,
username: username,
privateKey: '/home/steel/.ssh/id_rsa' // maybe parameterize this also
})
.then(function() {
ssh.execCommand(remoteCommand, { cwd:'/var/www' })
.then(function(result) {
console.log('STDOUT: ' + result.stdout)
console.log('STDERR: ' + result.stderr)
})
})
return null
},
})
}
Returning result
The above ssh code is just from the example page of node-ssh. If you want to return the result value, I think this will do it.
module.exports = (on, config) => {
on('task', {
ssh(params) {
const {username, host, remoteCommand} = params // destructure the argument
// returning promise, which is awaited by Cypress
return new Promise((resolve, reject) => {
const {NodeSSH} = require('node-ssh')
const ssh = new NodeSSH()
ssh.connect({
host: host,
username: username,
privateKey: '/home/steel/.ssh/id_rsa'
})
.then(function() {
ssh.execCommand(remoteCommand, { cwd:'/var/www' })
.then(function(result) {
resolve(result) // resolve to command result
})
})
})
},
})
}
In the test
cy.task('ssh', {username: 'username', host: '111.111.1.1', command: '\file.exe'})
.then(result => {
...
})
Only a single parameter is allowed for a task, so pass in an object and destructure it inside the task as shown above.
Related
Devs at my startup have switched login to a magic link system, in which you get inside after clicking a link on the email body.
I have set up a Mailsac email to receive mails containing magic links but I haven't been able to actually follow those links because of the following:
cy.request({
method: "GET",
url: "https://mailsac.com/api/addresses/xxxx#mailsac.com/messages",
headers: {
"Mailsac-Key": "here-goes-the-key",
},
}).then((res) => {
const magicLink = res.body[0].links[0];
cy.origin(magicLink, () => {
cy.visit('/')
});
});
I wasn't able to use cy.visit() either because the magic link URL is slightly different from the baseURL in this testing environment.
So my question is:
How could I follow this cumbersome link to find myself logged in home, or else, is there another way to deal with magic links?
Thanks
The docs say
A URL specifying the secondary origin in which the callback is to be executed. This should at the very least contain a hostname, and may also include the protocol, port number & path. Query params are not supported.
Not sure if this means the cy.visit() argument should not have query params, of just the cy.origin() parameter.
Try passing in the link
cy.request({
...
}).then((res) => {
const magicLink = res.body[0].links[0];
const magicOrigin = new URL(magicLink).origin
cy.origin(magicOrigin, { args: { magicLink } }, ({ magicLink }) => {
cy.visit(magicLink)
});
});
If that doesn't fix it, you could try using cy.request() but you'll have to observe where the token is stored after using the magicLink.
cy.request({
...
}).then((res) => {
const magicLink = res.body[0].links[0];
cy.request(magicLink).then(response =>
const token = response??? // find out where the auth token ends up
cy.setCookie(name, value) // for example
});
});
You need to pass the domain as the first parameter to origin, and do the visit within the callback function, something like this:
const magicLinkDomain = new Url(magicLink).hostname
cy.origin(magicLinkDomain, {args: magicLink}, ({ magicLink }) => {
cy.visit(magicLink);
//...
})
Reference: https://docs.cypress.io/api/commands/origin#Usage
Without the variables the server call works and gitlab is starting the pipeline.
But when I add variables to that call, it errors: "variables needs to be a map of key-valued strings".
This is my code:
axios
.post(`https://gitlab.myurl.com/api/v4/projects/${projectId}/trigger/pipeline`, {
ref: branch,
token: token,
variables: { STAGING_AREA: 'testing1', NOTIFY_STATUS: true, SLACK_USER_ID: 'xxxxx' }
})
.then(res => {
console.log('pipeline started:', res.data.web_url);
})
.catch(error => {
console.error('errorMessage', error);
});
What is the correct syntax for passing variables?
According to the docs, variable parameter should be in the form of variables[key]=value.
And the request is a multipart request so you need to use FormData.
Try running this code.
const pipelineTriggerBody = new FormData();
pipelineTriggerBody.append('ref', 'master'); // branch name
pipelineTriggerBody.append('token', 'CI_TOKEN');
pipelineTriggerBody.append('variables[STAGING_AREA]', 'testing1');
pipelineTriggerBody.append('variables[NOTIFY_STATUS]', true);
pipelineTriggerBody.append('variables[SLACK_USER_ID]', 'xxxxx');
axios
.post(
`https://gitlab.myurl.com/api/v4/projects/${projectId}/trigger/pipeline`,
pipelineTriggerBody
)
.then(res => {
console.log('pipeline started:', res.data.web_url);
})
.catch(error => {
console.error('errorMessage', error);
});
I was doing one thing wrong.
NOTIFY_STATUS: true
It seems that true can only be passed as a string:
NOTIFY_STATUS: 'true'
After this edit my code worked just fine.
I have compiled the C code using this command emcc add.c -o js_plumbing.js -s -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s MODULARIZE=1
This is my Vue component code -
public instance:any = {
ready: new Promise(resolve => {
Module({
onRuntimeInitialized() {
this.instance = Object.assign(this, {
ready: Promise.resolve()
});
resolve();
}
});
})
};
public draw_outline() {
this.instance.ready
.then(_ => this.result_web = this.instance.addTwoNumbers(2,2));
}
draw_outline is getting called when I click on a text element.
And this is the error I'm getting -
So after this error I went to generate file and just added export to the module and this error disappears. but now my function in C "addTwoNumbers" is not getting called from instance.
if I print the value of instance I get
Does anyone know how to proceed from here?
I figured that when compiling I needed to use USE_ES6_IMPORT_META=0 flag so that WebAssembly module will use an older version of the import.meta.url line of code for systems that don't recognize the import style. so the command looks like emcc add.c -o js_plumbing.js -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap'] -s ENVIRONMENT='web,worker' -s EXPORT_ES6=1 -s MODULARIZE=1 -s USE_ES6_IMPORT_META=0
This is my updated code -
Module().then(myModule => {
const result = myModule.ccall('addTwoNumbers',
'number',
['number', 'number'],
[4, 6]);
console.log("Value from wasm file", result);
});
My config file -
const path = require('path');
const contentBase = path.resolve(__dirname, '..', '..');
module.exports = {
configureWebpack: config => {
config.devServer = {
before(app) {
// use proper mime-type for wasm files
app.get('*.wasm', function (req, res, next) {
var options = {
root: contentBase,
dotfiles: 'deny',
headers: {
'Content-Type': 'application/wasm'
}
};
res.sendFile(req.url, options, function (err) {
if (err) {
next(err);
}
});
});
}
}
},
}
It is inside a function that I call on a click event . I can elaborate the whole process if someone is interested. It should not take this much time for anyone, I hope it helps others who have been looking for the solution. I realise I have not properly stated the problem in this post, I shall update everything here in a proper way soon.
Could somebody help with finding the most adequate way to run the same fixture with different preconditions using testcafe (fixture beforeEach)?
Given I have following fixture:
fixture('[Test] My Page')
.meta({ env: 'aat', mobile: 'true', author: 'me' })
.beforeEach(async t => {
await t.navigateTo(myPage.url)
await waitForReact(10000)
})
test('Page should load all data successfully', async t => {
const { Query: queries } = await t.ctx.graphQLTools.mockManagementClient.getCalls()
for (const q of Object.keys(queries)) {
for (const { args, context } of Object.keys(queries[q])) {
await t.expect(queries[q][args]).typeOf('undefined')
await t.expect(queries[q][context]).typeOf('undefined')
}
}
})
In the code example above I need to run this test for several times:
I'm an anonymous user
I'm the admin user
I'm a default user
I've tried the following code, but it looks cumbersome and will create complexity when I have more than 1 test in the fixture that needs to be checked(taken from https://testcafe-discuss.devexpress.com/t/multiple-execution-of-one-test-with-different-data/219):
const a = ['anonymous', 'logged In']
for (const user of a) {
test.meta({ wip: 'true' })(`Page should load all data successfully for ${user} user`, async t => {
if (R.equals('logged In', user)) {
await helpers.setCookie({ key: 'access_token', value: '123123123' })
await helpers.reloadPage()
}
const { Query: queries } = await t.ctx.graphQLTools.mockManagementClient.getCalls()
await t.expect(helpers.isEqlToEmptyQuery(queries.basket)).eql(true)
await t.expect(helpers.isEqlToEmptyQuery(queries.categories)).eql(true)
if (R.equals('logged In', user)) {
await t.expect(helpers.isEqlToEmptyQuery(queries.customer)).eql(true)
}
})
}
Is there a way I can run the whole fixture for 2-3 times with different beforeEach fixture hooks?
One simple solution could be to add three npm scripts in package.json:
"test": "testcafe chrome <all testcafe options>"
"test-anonymous": "npm test -- --user=anonymous"
"test-admin": "npm test -- --user=admin"
"test-default": "npm test -- --user=default"
Then read this custom command-line option in the beforeEach as I explained in Testcafe - Test command line argument outside test case
I'm using Express Graphql server with react native and Relay. My device does connects to the subscription but it does not subscribe to it. Here's my index.js on the server
const subscriptionServer = SubscriptionServer.create(
{
execute,
subscribe,
schema,
onOperation: (message, params, webSocket) => {
console.log(params)
return params;
},
onConnect: () => {
// My device does connects
console.log("client connected")
}
},
{
server,
path: '/subscriptions'
},
);
app.use('/graphql', graphqlHTTP({
schema,
graphiql: true
}));
app.use('/graphiql', graphiqlExpress({
endpointURL: '/graphql',
subscriptionsEndpoint: `ws://127.0.0.1:8080/subscriptions`
}));
server.listen(PORT, ()=> {
console.log("Groceries running on port " + PORT)
console.log(
`subscriptions is now running on ws://localhost:${PORT}/subscriptions'}`
);
});
The resolver for subscription on the server, it was quite troublesome to figure out since everyone is using executable schema from apolloGraphql.
export default {
type: OrderEdges,
args: {
ShopId: {type: GraphQLID},
},
subscribe: withFilter(() => pubsub.asyncIterator('orderConfirmed'), (payload, variables) => {
console.log(payload)
console.log(variables)
return payload.orderConfirmed.node.ShopId == variables.ShopId;
}),
}
Now the react-native client. My subscription setup with relay environment.
const setupSubscriptions = (config, variables, cacheConfig, observer) => {
const query = config.text; //does console logs the query
const subscriptionClient = new SubscriptionClient(`ws://192.168.0.100:8080/subscriptions`, {reconnect:true});
subscriptionClient.request({query, variables}, (err, result) => {
console.log(err) // doesn't get call inside the request method
observer.onNext(data:result)
})
}
My subscription method,
export default function() {
const variables = {
ShopId: shop.getShop()[0].id
}
requestSubscription(
environment,
{
subscription,
variables,
onCompleted: (res, err) => {
console.log(res)
console.log(err)
},
updater: (store) => {...},
onError: error => console.error(error),
onNext: (response) => {console.log(response)}
});
}
the component where I'm calling to subscribe,
import subscription from '../../GraphQLQueries/subscriptions/orderConfirmed';
class OrdersBox extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
//initializing subscription
orderSubscriptions();
}
When the device starts the app, my device is connected to the web socket as I can see the console.log statement inside the onConnect method in SubscriptionServer. But when the payload is published after a mutation, the subscribe method doesn't get called. I can't seem to figure out what I'm doing wrong. Maybe it's some react-native specific config that I'm missing cuz everything seems to work fine when I test it on graphiql.
I can't find any example of react-native and relay subscriptions used with express graphql.
note: Everything is working when I use subscription with graphiql. But not with react-native and relay.
Thanks in advance guys
....
I wasn't returning the subscriptionClient.request method. Adding a return statement solved the problem. You don't have to return when using subscribe method in subscriptions-transport-ws#0.8.3. But version 0.9.1 replaces the subscribe function with request which does require it to return.
try:
function setupSubscription(config, variables, cacheConfig, observer) {
const query = config.text;
const subscriptionClient = new SubscriptionClient(websocketURL, {
reconnect: true
});
const client = subscriptionClient.request({ query, variables }).subscribe({
next: result => {
observer.onNext({ data: result.data });
},
complete: () => {
observer.onCompleted();
},
error: error => {
observer.onError(error);
}
});
return {
dispose: client.unsubscribe
};
}
subscriptions-transport-ws#0.9.1