How to catch a SMS from Twilio with Cypress IO? - javascript

I have found this code on one of the tutorials to catch SMS from Twilio and pass it to ur webdriver test. I need help to catch the sms using Cypress. I need help using async-await instead of browser.call with Cypress.
const accountSid = 'YOUR_SID';
const authToken = 'YOUR_TOKEN';
const client = require('twilio')(accountSid, authToken);
describe('OTP', () => {
it('Login with OTP', () => {
const username = $('#login_field');
const pass = $('#password');
const signInBtn = $('input[type="submit"]');
const otpField = $('#otp');
const verifyBtn = $(
'form[action="/sessions/two-factor"] button[type="submit"]'
);
browser.url('https://github.com/login');
username.setValue('your_email#mail.com');
pass.setValue('your_pass123');
signInBtn.click();
// Get OTP ...
const otp = browser.call(() => {
return new Promise((resolve, reject) => {
try {
client.messages.list({ limit: 1 }).then((messages) =>
messages.forEach((m) => {
// console.log(m.body.match(/\d+/)[0]);
resolve(m.body.match(/\d+/)[0]);
})
);
} catch (error) {
reject(error);
}
});
});
otpField.setValue(otp);
verifyBtn.click();
expect(browser).toHaveUrl('https://github.com/');
});
});

Manzeel Uprety you can try my solution:
const accountSid = 'AC793683c4982a14f01714321bd3f90ca7';
const authToken = '819068e54369ac58bb8aad976fa517bc';
const githubEmail = 'your_github_email'
const githubPassword = 'your_github_password'
describe('Login with github credentials', () => {
beforeEach(()=>{
cy.visit('https://github.com/login');
cy.get('#login_field').type(githubEmail);
cy.get('#password').type(githubPassword);
cy.get('input[type="submit"]').click()
})
it('Get SMS and apply it in 2FA form', () => {
cy.request({
method: 'GET',
url: `https://api.twilio.com/2010-04-01/Accounts/${accountSid}/Messages.json`,
auth: {
username: accountSid,
password: authToken,
AuthMethod: 'BasicAuth',
}
})
.its('body').then((res) => {
cy.wait(1500) //wait for SMS
const otpcode = res.messages[0].body.substring(0, 6)
cy.get('#otp').type(otpcode);
cy.url().should('eq', 'https://github.com/');
})
});
});

Related

Browser push notification is not showing

I tried to append push notification to a Nextjs app. Referring to this tutorial but the push notification is not showing.
https://www.youtube.com/watch?v=HlYFW2zaYQM
Of course I turn on authorization of notification in chrome browser.
_app.tsx
import { AppProps } from "next/app"
import { useEffect } from "react"
const publicVapidKey = 'blablabla...'
const send = async () => {
console.log("registering serviceWorker")
const register = await navigator.serviceWorker.register("/sw.js", {
scope: "/",
})
console.log("serviceWorker is registered")
console.log("registering push")
const subscription = await register.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey),
})
console.log("push is registered")
console.log("sending push..")
await fetch("http://localhost:8000/push", {
method: "POST",
body: JSON.stringify(subscription),
headers: {
"content-type": "application/json",
},
})
console.log("have sent push")
}
// change base64 of VapidKey to Uint8Array
const urlBase64ToUint8Array = (base64String: string) => {
let padding = "=".repeat((4 - (base64String.length % 4)) % 4)
let base64 = (base64String + padding).replace(/\-/g, "+").replace(/_/g, "/")
let rawData = window.atob(base64)
let outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}
function MyApp({ Component, pageProps }: AppProps) {
const { globalIsModalOpen } = useStore()
useEffect(() => {
(async () => {
const result = await Notification.requestPermission()
if (result === "granted") {
console.log("auth ok")
}
})()
if ("serviceWorker" in navigator) {
send().catch((err) => console.error(err))
}
}, [])
return (
<div>
This is example
</div>
)
}
export default MyApp
public/sw.js
self.addEventListener("push", (e) => {
const data = e.data.json();
console.log("have got push notification");
self.registration.showNotification(data.title, {
body: "This is example",
icon:
"https://blablabla...",
});
});
index.js (backend file, separated from Nextjs directory)
const fetch = require('node-fetch')
const express = require('express')
const cors = require('cors')
const webpush = require('web-push')
const app = express()
app.use(cors())
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const publicVapidKey = 'blablabla...';
const privateVapidKey = 'blablabla...';
webpush.setVapidDetails('mailto:example#example.com', publicVapidKey, privateVapidKey);
app.post('/push', async (req, res) => {
const subscription = req.body;
res.status(201).json({ 'success': true })
const payload = JSON.stringify({ title: 'push notification test' });
webpush.sendNotification(subscription, payload).catch(err => console.error(err))
})
app.listen(8000, () => {
console.log('server is running on 8000')
})

TypeError: AWS.DynamoDB.DocumentClient is not a constructor when testing with Jest

I am running jest tests to test a dynamodb.js file and a create.js file that uses the dynamodb.js file. The create.js module is generic and can insert into any tables by having the param object constructed and passed into it. However, I have been getting the error below and I need help with this.
TypeError: AWS.DynamoDB.DocumentClient is not a constructor
__mock__ folder
const getMock = jest.fn().mockImplementation(() => {
return {
promise() {
return Promise.resolve({});
}
};
});
const putMock = jest.fn().mockImplementation(() => {
return {
promise() {
return Promise.resolve({});
}
};
});
// eslint-disable-next-line func-names
function DynamoDB() {
return {
DocumentClient: jest.fn(() => ({
get: getMock,
put: putMock
}))
};
}
const AWS = { DynamoDB, getMock, putMock };
module.exports = AWS;
dynamodb.js
const AWS = require('aws-sdk');
const http = require('http');
const https = require('https');
const url = require('url');
module.exports = endpoint => {
const { protocol } = url.parse(endpoint || '');
const agentConfig = {
keepAlive: true,
keepAliveMsecs: 20000
};
const httpOptions =
protocol === 'http:' ? { agent: new http.Agent(agentConfig) } : { agent: new https.Agent(agentConfig) };
const db = new AWS.DynamoDB({
endpoint,
httpOptions
});
const docClient = new AWS.DynamoDB.DocumentClient({
service: db
});
return {
docClient,
db
};
};
dynamodb.spec.js
const AWS = require('aws-sdk');
const dynamodb = require('../../../src/dynamodb');
describe('dynamodb.js', () => {
beforeEach(() => {
// jest.resetModules();
});
test('calls generic-dynamodb-lib dynamodb', async () => {
dynamodb('http://localhost:8001');
expect(AWS.DynamoDB).toHaveBeenCalled();
expect(AWS.DynamoDB.DocumentClient).toHaveBeenCalled();
});
});
create.js
// Imports here
const create = async (log, docClient, table, tableRecord) => {
try {
await docClient.put({ TableName: table, Item: tableRecord }).promise();
} catch (error) {
log.error({ message: 'DynamoDB error', ...error });
throw Error.internal();
}
return tableRecord;
};
module.exports = create;
I have also tried replacing the manual mock in mock with a doMock block but still continued getting the same error above.
Once I get past this, how do I test create.js considering that docClient.js is being passed into the function? Thank you very much.
DocumentClient is supposed to be static property while it was mocked to be instance property.
It should be:
const DynamoDB = jest.fn().mockReturnValue({});
DynamoDB.DocumentClient = jest.fn().mockReturnValue({
get: getMock,
put: putMock
});
Thank you very much for your responses.
I had already found a way to solve the problem before seeing the response here.
I did not need place any mocks in the __mock__ directory eventually.
Please see the tests that I came up with:
create.spec.js
const AWS = require('aws-sdk');
const dynamodb = require('../../../src/dynamodb');
const create = require('../../../src/create');
describe('create.js', () => {
beforeEach(() => {
jest.resetModules();
});
test('calls DocumentClient put with a successful outcome', async () => {
const log = { error: jest.fn() };
const fakePut = jest.fn().mockImplementation(() => {
return {
promise() {
return Promise.resolve({});
}
};
});
AWS.DynamoDB.DocumentClient = jest.fn(() => ({
put: fakePut
}));
const document = {
brands: ['visa', 'mc', 'amex', 'maestro', 'diners', 'discover', 'jcb']
};
const { docClient } = dynamodb('https://localhost:8001');
await create(log, docClient, 'a-table-name', {
countryCode: 'US',
merchantAccount: 'MerchantAccountUS',
expireAt: 1593814944,
document
});
expect(create).toEqual(expect.any(Function));
expect(fakePut).toHaveBeenCalled();
expect(fakePut).toHaveBeenCalledWith({
TableName: 'a-table-name',
Item: {
countryCode: 'US',
merchantAccount: 'MerchantAccountUS',
expireAt: 1593814944,
document
}
});
});
test('calls DocumentClient put with unsuccessful outcome', async () => {
const log = { error: jest.fn() };
const fakePut = jest.fn().mockImplementation(() => {
throw Error.internal();
});
AWS.DynamoDB.DocumentClient = jest.fn(() => ({
put: fakePut
}));
const document = {
brands: ['visa', 'mc', 'amex', 'maestro', 'diners', 'discover', 'jcb']
};
const { docClient } = dynamodb('https://localhost:8001');
let thrownError;
try {
await create(log, docClient, 'a-table-name', {
countryCode: 'US',
merchantAccount: 'MerchantAccountUS',
expireAt: 1593814944,
document
});
} catch (e) {
thrownError = e;
}
expect(create).toEqual(expect.any(Function));
expect(fakePut).toHaveBeenCalled();
expect(fakePut).toHaveBeenCalledWith({
TableName: 'a-table-name',
Item: {
countryCode: 'US',
merchantAccount: 'MerchantAccountUS',
expireAt: 1593814944,
document
}
});
expect(thrownError).toEqual(Error.internal());
});
});
dynamodb.spec.js
const AWS = require('aws-sdk');
const http = require('http');
const https = require('https');
const url = require('url');
const dynamodb = require('../../../src/dynamodb');
const fakeFunction = jest.fn().mockImplementation(() => {});
const FakeDynamoDB = jest.fn(() => ({
DocumentClient: fakeFunction
}));
AWS.DynamoDB = FakeDynamoDB;
const fakeGet = fakeFunction;
const fakePut = fakeFunction;
const FakeDocumentClient = jest.fn(() => ({
get: fakeGet,
put: fakePut
}));
AWS.DynamoDB.DocumentClient = FakeDocumentClient;
describe('dynamodb.js', () => {
beforeEach(() => {
jest.resetModules();
});
test('calls DynamoDB and DocumentClient constructors with http protocol and with endpoint present', () => {
const fakeParse = jest.fn().mockImplementation(() => 'http');
url.parse = fakeParse;
const fakeHttpAgent = jest.fn().mockImplementation(() => {});
http.Agent = fakeHttpAgent;
dynamodb('http://localhost:8001');
expect(FakeDynamoDB).toHaveBeenCalled();
expect(FakeDocumentClient).toHaveBeenCalled();
});
test('calls DynamoDB and DocumentClient constructors with https protocol and with endpoint present', () => {
const fakeParse = jest.fn().mockImplementation(() => 'https');
url.parse = fakeParse;
const fakeHttpsAgent = jest.fn().mockImplementation(() => {});
https.Agent = fakeHttpsAgent;
dynamodb('https://localhost:8001');
expect(FakeDynamoDB).toHaveBeenCalled();
expect(FakeDocumentClient).toHaveBeenCalled();
});
});

How to make api endpoint target user's localhost when deployed to Heroku

I have this api which works fine when running locally. But, once it is deployed to Heroku i get a error 503 which is because it tries to target localhost on Heroku's server and not the user's localhost. Is there a way to make this target the user's localhost instead?
The frontend is React. Here's the code in React that fetches this api every 5sec.
axiosFunc = () => {
const { user } = this.props.auth;
console.log(user);
axios.get(`api/avaya/${user.id}`).then((res) => console.log(res));
};
timer = (time) => {
const date = new Date(time);
return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
};
componentDidMount() {
this.axiosFunc();
this.interval = setInterval(this.axiosFunc, 5000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
and this is the API on the backend with express
const router = require("express").Router();
const xml2js = require("xml2js");
const Avaya = require("../../models/Avaya");
const User = require("../../models/User");
router.route("/:id").get(async (req, res) => {
const user = await User.findById(req.params.id);
const axios = require("axios");
axios({
method: "post",
baseURL: `http://127.0.0.1:60000/onexagent/api/registerclient?name=${user.username}`,
timeout: 2000,
})
.then((reg) => {
xml2js
.parseStringPromise(reg.data, { mergeAttrs: true })
.then((result) => {
if (result.RegisterClientResponse.ResponseCode[0] === "0") {
const clientId = result.RegisterClientResponse.ClientId[0];
user.avayaClientId = clientId;
user.save();
}
const clientId = user.avayaClientId;
axios({
method: "post",
url: `http://127.0.0.1:60000/onexagent/api/nextnotification?clientid=${clientId}`,
}).then((notification) => {
xml2js
.parseStringPromise(notification.data, { mergeAttrs: true })
.then((result) => {
const notifType = [];
const notifDetails = [];
for (let i in result.NextNotificationResponse) {
notifType.push(i);
}
const arranged = {
NotificationType: notifType[1],
ResponseCode:
result.NextNotificationResponse[notifType[0]][0],
};
for (let i in result.NextNotificationResponse[
notifType[1]
][0]) {
notifDetails.push(i);
}
for (let i = 0; i < notifDetails.length; i++) {
arranged[[notifDetails[i]][0]] =
result.NextNotificationResponse[notifType[1]][0][
notifDetails[i]
][0];
}
for (let i in arranged) {
if ("Outbound" in arranged) {
arranged.CallType = "Outbound";
} else if ("Inbound" in arranged)
arranged.CallType = "Inbound";
else {
arranged.CallType = " ";
}
}
if (
arranged.NotificationType === "VoiceInteractionCreated" ||
arranged.NotificationType === "VoiceInteractionMissed" ||
arranged.NotificationType === "VoiceInteractionTerminated"
) {
const newLogs = new Avaya({
notification: arranged,
});
newLogs.owner = user;
newLogs.save();
user.avayaNotifications.push(newLogs),
user
.save()
.then((logs) => res.json(logs))
.catch((err) => res.status(400).json("Error: " + err));
} else {
res.send("Nothing to record");
}
});
});
});
})
.catch((err) => res.status(503).json(err));
});
router.route("/history/:username").get(async (req, res) => {
const user = await User.findOne({ username: [`${req.params.username}`] });
Avaya.find({ owner: [`${await user.id}`] }).then((user) => res.json(user));
});
module.exports = router;
EDIT: I was able to fix thanks to #Molda
using fetch instead of axios doesn't result in cors error.
New frontend code
getLogs = async () => {
const { user } = this.props.auth;
const reg = await fetch(
`http://127.0.0.1:60000/onexagent/api/registerclient?name=${user.id}`
);
let regData = await reg.text();
let regxml = new XMLParser().parseFromString(regData);
if (regxml.attributes.ResponseCode === "0") {
axios.post(`/api/avaya/register/${user.id}`, regxml);
console.log(regxml.attributes.ResponseCode);
}
let resp = await fetch(`/api/avaya/getid/${user.id}`);
let clientId = await resp.text();
let logs = await fetch(
`http://127.0.0.1:60000/onexagent/api/nextnotification?clientid=${clientId}`
);
let data = await logs.text();
var xml = new XMLParser().parseFromString(data);
axios.post(`/api/avaya/getlogs/${user.id}`, xml);
};
timer = (time) => {
const date = new Date(time);
return `${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
};
componentDidMount() {
this.getLogs();
this.interval = setInterval(this.getLogs, 5000);
}
New backend code:
const router = require("express").Router();
const Avaya = require("../../models/Avaya");
const User = require("../../models/User");
router.route("/register/:id").post(async (req, res) => {
const user = await User.findById(req.params.id);
const clientId = req.body.attributes.ClientId;
user.avayaClientId = clientId;
user.save();
});
router.route("/getid/:id").get(async (req, res) => {
const user = await User.findById(req.params.id);
res.send(user.avayaClientId);
});
router.route("/getlogs/:id").post(async (req, res) => {
const user = await User.findById(req.params.id);
const arranged = {
NotificationType: req.body.children[0].name,
ResponseCode: req.body.attributes.ResponseCode,
CallType: " ",
};
for (let i in req.body.children[0].attributes) {
if (i === "Outbound") {
arranged.CallType = "Outbound";
}
if (i === "Inbound") {
arranged.CallType = "Inbound";
}
arranged[i] = req.body.children[0].attributes[i];
}
console.log(arranged);
if (
arranged.NotificationType === "VoiceInteractionCreated" ||
arranged.NotificationType === "VoiceInteractionMissed" ||
arranged.NotificationType === "VoiceInteractionTerminated"
) {
const newLogs = new Avaya({
notification: arranged,
});
newLogs.owner = user;
newLogs.save();
user.avayaNotifications.push(newLogs),
user
.save()
.then((logs) => res.json(logs))
.catch((err) => res.status(400).json("Error: " + err));
} else {
res.send("Nothing to record");
}
});
router.route("/history/:username").get(async (req, res) => {
const user = await User.findOne({ username: [`${req.params.username}`] });
Avaya.find({ owner: [`${await user.id}`] }).then((user) => res.json(user));
});
module.exports = router;
I really don't get the part of (requesting with Axios in API)
Is this a third party API ?
But I suggest you to use (.env) which is a file in your root folder contains the development config like base URLs, expire tokens, API keys ... etc
and when you upload to Heroku you have to make a (.env) in Heroku app and but your config
Let's take an example
in my development mode, my .env looks like
app_url = localhost:4000
port = 4000
db = development_api
db_username = root
db_password =
db_engine = mysql2
in my production mode, my .env looks like
app_url = http://appsomething.heroku.com
port = 80
db = production_api
db_username = root
db_password = 3210LDWAK#AALKQ
db_engine = mysql2
and read more about how to use .ENV

Always throws registration failed error while subscribing push notifications

I am working on solutions using which i can send desktop push notification to subscribed clients.
I have created basic solution in where whenever user click on button i ask user for whether they want to allow notifications for my app or not!
I am getting an error of "Registration failed - permission denied" whenever i click on button for first time.
So that i am not able to get required endpoints to save at backend
Here is my code
index.html
<html>
<head>
<title>PUSH NOT</title>
<script src="index.js"></script>
</head>
<body>
<button onclick="main()">Ask Permission</button>
</body>
</html>
index.js
const check = () => {
if (!("serviceWorker" in navigator)) {
throw new Error("No Service Worker support!");
} else {
console.log("service worker supported")
}
if (!("PushManager" in window)) {
throw new Error("No Push API Support!");
} else {
console.log("PushManager worker supported")
}
};
const registerServiceWorker = async () => {
const swRegistration = await navigator.serviceWorker.register("/service.js?"+Math.random());
return swRegistration;
};
const requestNotificationPermission = async () => {
const permission = await window.Notification.requestPermission();
// value of permission can be 'granted', 'default', 'denied'
// granted: user has accepted the request
// default: user has dismissed the notification permission popup by clicking on x
// denied: user has denied the request.
if (permission !== "granted") {
throw new Error("Permission not granted for Notification");
}
};
const main = async () => {
check();
const swRegistration = await registerServiceWorker();
const permission = await requestNotificationPermission();
};
// main(); we will not call main in the beginning.
service.js
// urlB64ToUint8Array is a magic function that will encode the base64 public key
// to Array buffer which is needed by the subscription option
const urlB64ToUint8Array = base64String => {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const saveSubscription = async subscription => {
console.log("Save Sub")
const SERVER_URL = "http://localhost:4000/save-subscription";
const response = await fetch(SERVER_URL, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(subscription)
});
return response.json();
};
self.addEventListener("activate", async () => {
try {
const applicationServerKey = urlB64ToUint8Array(
"BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM"
);
const options = { applicationServerKey, userVisibleOnly: true };
const subscription = await self.registration.pushManager.subscribe(options);
console.log(JSON.stringify(subscription))
const response = await saveSubscription(subscription);
} catch (err) {
console.log(err.code)
console.log(err.message)
console.log(err.name)
console.log('Error', err)
}
});
self.addEventListener("push", function(event) {
if (event.data) {
console.log("Push event!! ", event.data.text());
} else {
console.log("Push event but no data");
}
});
Also i have created a bit of backend as well
const express = require("express");
const cors = require("cors");
const bodyParser = require("body-parser");
const webpush = require('web-push')
const app = express();
app.use(cors());
app.use(bodyParser.json());
const port = 4000;
app.get("/", (req, res) => res.send("Hello World!"));
const dummyDb = { subscription: null }; //dummy in memory store
const saveToDatabase = async subscription => {
// Since this is a demo app, I am going to save this in a dummy in memory store. Do not do this in your apps.
// Here you should be writing your db logic to save it.
dummyDb.subscription = subscription;
};
// The new /save-subscription endpoint
app.post("/save-subscription", async (req, res) => {
const subscription = req.body;
await saveToDatabase(subscription); //Method to save the subscription to Database
res.json({ message: "success" });
});
const vapidKeys = {
publicKey:
'BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM',
privateKey: 'mHSKS-uwqAiaiOgt4NMbzYUb7bseXydmKObi4v4bN6U',
}
webpush.setVapidDetails(
'mailto:janakprajapati90#email.com',
vapidKeys.publicKey,
vapidKeys.privateKey
)
const sendNotification = (subscription, dataToSend='') => {
webpush.sendNotification(subscription, dataToSend)
}
app.get('/send-notification', (req, res) => {
const subscription = {endpoint:"https://fcm.googleapis.com/fcm/send/dLjyDYvI8yo:APA91bErM4sn_wRIW6xCievhRZeJcIxTiH4r_oa58JG9PHUaHwX7hQlhMqp32xEKUrMFJpBTi14DeOlECrTsYduvHTTnb8lHVUv3DkS1FOT41hMK6zwMvlRvgWU_QDDS_GBYIMRbzjhg",expirationTime:null,keys:{"p256dh":"BE6kUQ4WTx6v8H-wtChgKAxh3hTiZhpfi4DqACBgNRoJHt44XymOWFkQTvRPnS_S9kmcOoDSgOVD4Wo8qDQzsS0",auth:"CfO4rOsisyA6axdxeFgI_g"}} //get subscription from your databse here.
const message = 'Hello World'
sendNotification(subscription, message)
res.json({ message: 'message sent' })
})
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Please help me
Try the following code:
index.js
const check = () => {
if (!("serviceWorker" in navigator)) {
throw new Error("No Service Worker support!");
} else {
console.log("service worker supported")
}
if (!("PushManager" in window)) {
throw new Error("No Push API Support!");
} else {
console.log("PushManager worker supported")
}
};
const saveSubscription = async subscription => {
console.log("Save Sub")
const SERVER_URL = "http://localhost:4000/save-subscription";
const response = await fetch(SERVER_URL, {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(subscription)
});
return response.json();
};
const urlB64ToUint8Array = base64String => {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, "+")
.replace(/_/g, "/");
const rawData = atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
};
const registerServiceWorker = async () => {
return navigator.serviceWorker.register("service.js?"+Math.random()).then((swRegistration) => {
console.log(swRegistration);
return swRegistration;
});
};
const requestNotificationPermission = async (swRegistration) => {
return window.Notification.requestPermission().then(() => {
const applicationServerKey = urlB64ToUint8Array(
"BFPtpIVOcn2y25il322-bHQIqXXm-OACBtFLdo0EnzGfs-jIGXgAzjY6vNapPb4MM1Z1WuTBUo0wcIpQznLhVGM"
);
const options = { applicationServerKey, userVisibleOnly: true };
return swRegistration.pushManager.subscribe(options).then((pushSubscription) => {
console.log(pushSubscription);
return pushSubscription;
});
});
};
const main = async () => {
check();
const swRegistration = await registerServiceWorker();
const subscription = await requestNotificationPermission(swRegistration);
// saveSubscription(subscription);
};
service.js
self.addEventListener("push", function(event) {
if (event.data) {
console.log("Push event!! ", event.data.text());
} else {
console.log("Push event but no data");
}
});
I can think of three reasons that the permission is denied
1) your site is not on https (including localhost that is not on https), the default behaviour from chrome as far as i know is to block notifications on http sites. If that's the case, click on the info icon near the url, then click on site settings, then change notifications to ask
2) if you are on Safari, then safari is using the deprecated interface of the Request permission, that is to say the value is not returned through the promise but through a callback so instead of
Notification.requestPermission().then(res => console.log(res))
it is
Notification.requestPermission(res => console.log(res))
3) Your browser settings are blocking the notifications request globally, to ensure that this is not your problem run the following code in the console (on a secured https site)
Notification.requestPermission().then(res => console.log(res))
if you receive the alert box then the problem is something else, if you don't then make sure that the browser is not blocking notifications requests

Can't figure out why my app.get is being run twice?

I have a app.get which inside of it is quite a bit of logic. Which everything works great aside from some of the logic being called twice for some reason. I have noticed when I was saving something to by db that it would save two rows.
So I put a console.log in that area and sure enough it was logging it twice.
Any reason why this is happening?
app.get('/shopify/callback', (req, res) => {
const { shop, hmac, code, state } = req.query;
const stateCookie = cookie.parse(req.headers.cookie).state;
if (state !== stateCookie) {
return res.status(403).send('Request origin cannot be verified');
}
if (shop && hmac && code) {
// DONE: Validate request is from Shopify
const map = Object.assign({}, req.query);
delete map['signature'];
delete map['hmac'];
const message = querystring.stringify(map);
const providedHmac = Buffer.from(hmac, 'utf-8');
const generatedHash = Buffer.from(
crypto
.createHmac('sha256', config.oauth.client_secret)
.update(message)
.digest('hex'),
'utf-8'
);
let hashEquals = false;
try {
hashEquals = crypto.timingSafeEqual(generatedHash, providedHmac)
} catch (e) {
hashEquals = false;
};
if (!hashEquals) {
return res.status(400).send('HMAC validation failed');
}
// DONE: Exchange temporary code for a permanent access token
const accessTokenRequestUrl = 'https://' + shop + '/admin/oauth/access_token';
const accessTokenPayload = {
client_id: config.oauth.api_key,
client_secret: config.oauth.client_secret,
code,
};
request.post(accessTokenRequestUrl, { json: accessTokenPayload })
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// DONE: Use access token to make API call to 'shop' endpoint
const shopRequestUrl = 'https://' + shop + '/admin/shop.json';
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken,
}
request.get(shopRequestUrl, { headers: shopRequestHeaders })
.then((shopResponse) => {
const response = JSON.parse(shopResponse);
const shopData = response.shop;
console.log('BEING CALLED TWICE...')
res.render('pages/brand_signup',{
shop: shopData.name
})
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
} else {
res.status(400).send('Required parameters missing');
}
});

Categories