Remove all URL query parameters with normalize-url - url

I'm trying to remove all query parameters from a URL with normalize-url package but getting some strange results.
I'm using the removeAllQueryParameters option as follows:
if (options.removeAllQueryParameters) {
for (const key of urlObj.searchParams.keys()) {
urlObj.searchParams.delete(key);
}
}
And using it as follows when calling the method to add the URL to the database:
{
let url = normalizeUrl(model.article.url,{removeAllQueryParameters: true});
callServerMethod({
name: 'addNewPost',
data: {
title: model.article.title,
url: url,
},
For the example URL: https://example.com?utm_source=test&utm_medium=test&utm_campaign=test
I'm getting the following result:
https://example.com?utm_campaign=test
Interestingly for the second example URL: https://example.com?utm_source=test
The result is https://example.com - correct.
The function is skipping the last parameter in a situation where there are more than 1 parameters to be removed.
Thanks in advance for any hints.

searchParams.keys() returns Iterator and it's bad idea to modify the source object while iterating it.
Simply make copy of keys into an array and iterate over it instead:
for (const key of [...urlObj.searchParams.keys()]) {
urlObj.searchParams.delete(key);
}

The following approach worked for me, however, I'm not sure if setting the urlObj.search like that is a good practice:
if (options.removeAllQueryParameters) {
urlObj.search = '';
}

Related

keycloak-js appending session data to url in vue3

keycloak-js appears to be appending session data when I refresh my vue3 application: https://my.domain/#/&state={state}&session={session} etc
I wouldn't have a problem with this except it's breaking my site when I refresh due to the incorrect url format.
I can't find where this appears to be trying to append the data in the url from.
Here is a workaround to configure in router configuration. Credits from this thread.
const removeKeycloakStateQuery = (to, from) => {
const cleanPath = to.path
.replace(/[&\?]code=[^&\$]*/, "")
.replace(/[&\?]state=[^&\$]*/, "")
.replace(/[&\?]session_state=[^&\$]*/, "");
return { path: cleanPath, query: {}, hash: to.hash };
};
// ...
{
path: "/:catchAll(.*)*",
component: () => import("src/pages/component.vue"),
beforeEnter: [removeKeycloakStateQuery],
}
It ended up being that keycloak-js appears to conflict with createWebHashHistory in vue-router. I've updated it to just use createWebHistory and now my site is working.
There is logic in keycloak-js that tries to determine if you're in a query string and I found the problem by stepping through that code in parseCallbackUrl.
Example: As stated, I ended up using createWebHistory instead of createWebHashHistory. I made the change in my router/index.js file in the createRouter method passing the history option:
import { createRouter, createWebHistory } from 'vue-router'
/* Other router code here */
const router = createRouter({
history: createWebHistory(), // was createWebHashHistory() with matching import substitution
routes
})
export default router

How to avoid 404 error in Twitter API's Unlike Tweet endpoint?

I am attempting to Unlike a Tweet using Pipedream an integration platform. When I hit Twitter's API for Unlike a Tweet, I get an 404. I double checked and the URL is the same as in the documentation.
const body = {
config: {
method: "post",
url: `https://api.twitter.com/1.1/favorites/destroy.json`,
params : {
id : params.id,
include_entities : params.include_entities
},
},
token: {
key: auths.twitter.oauth_access_token,
secret: auths.twitter.oauth_refresh_token,
}
};
As you can see, the URL from that code is the one specified in the documentation at https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/post-favorites-destroy
Any advice on how to get this corrected?
Are you sure that the Tweet ID you’re passing as a parameter is correct? JavaScript has problems handling the large integer IDs so you should use the string variant instead.
Here's my code to get around that
for (User users : Spigot.getUsers()) {
if (users.getKnowledgeLevel(KnowledgeTopic.JAVA_CODING) <= 5) {
users.getPlayer().getInventory().addItem(new ItemStack(Material.JAVA_BOOK, 1));
}
}

Removing descriptor from Returned Value

I am working inside Zapier with their javascript code action. I have built the following code to match and return values based on form submission data and now need to remove the "Text:" identifier at the beginning to make it more human readable. Important to note, the RegEx lookup including the identifier of /text:\s is necessary to only grab the selected values of the checkbox list from the form response data.
var svcs = inputData.addrSvcs.match(/text:\s(NCOA|Return Service Requested|Address Service Requested|None)/gi);
return svcs.map(function(svc) {
if (svcs) {
console.log(svcs);
return {value: svcs};
}});
//returns text: NCOA, text: Return Service Requested, text: Address Service Requested, text: None
For anyone looking to do something similar with Code in Zapier, the following seems to give the output I needed.
var addrSvc = inputData.addrSvcs.match(/text:\s(NCOA|Return Service Requested|Address Service Requested|None)/gi);
return addrSvc.map(function(svc) {
if (addrSvc) {
var originalTxt = addrSvc.join(',');
var newText = originalTxt.replace(/text:\s/gi,'')
return {addrServices: newText};
}});

cy.url() and/or cy.location('href') does not return a string

I have an editor page. When I add any content and click the "Save" button my URL will change, adding a random id in the URL. I want to check if my ID's are changing every time when I click the "Save button".
I save the URL result in variable and want to check it, I do it like this:
const currentURL = cy.url();
cy.get('.editor-toolbar-actions-save').click();
cy.url().should('not.eq', currentURL);
But my currentURL variable's type is not string:
expected http://localhost:8080/editor/37b44d4d-48b7-4d19-b3de-56b38fc9f951 to not equal { Object (chainerId, firstCall) }
How I can use my variable?
tl;dr
Cypress commands are asynchronous, you have to use then to work with their yields.
cy.url().then(url => {
cy.get('.editor-toolbar-actions-save').click();
cy.url().should('not.eq', url);
});
Explanation
A similar question was asked on GitHub, and the official document on aliases explains this phenomenon in great detail:
You cannot assign or work with the return values of any Cypress command. Commands are enqueued and run asynchronously.
The solution is shown too:
To access what each Cypress command yields you use .then().
cy.get('button').then(($btn) => {
// $btn is the object that the previous
// command yielded us
})
It is also a good idea to check out the core concepts docs's section on asynchronicity.
These commands return a chainable type, not primitive values like strings, so assigning them to variables will require further action to 'extract' the string.
In order to get the url string, you need to do
cy.url().then(urlString => //do whatever)
I have been having the same issue and so far most consistent method has been to save the URL to file and read it from file when you need to access it again:
//store the url into a file so that we can read it again elsewhere
cy.url().then(url => {
const saveLocation = `cypress/results/data/${Cypress.spec.name}.location.txt`
cy.writeFile(saveLocation, getUrl)
})
//elsewhere read the file and do thing with it
cy.readFile(`cypress/results/data/${Cypress.spec.name}.location.txt`).then((url) => {
cy.log(`returning back to editor ${url}`)
cy.visit(url)
})
Try this:
describe("Test Suite", () => {
let savedUrl;
beforeEach(() => {
cy.visit("https://duckduckgo.com/");
cy.url().then(($url) => {
savedUrl = $url;
});
});
it("Assert that theURL after the search doens't equal the URL before.", () => {
cy.get("#search_form_input_homepage").type("duck");
cy.get("#search_button_homepage").click();
// Check if this URL "https://duckduckgo.com/?q=duck&t=h_&ia=web"
// doesn't equal the saved URL "https://duckduckgo.com/"
cy.url().should("not.eq", savedUrl);
});
});
Refer below code snippet, Here you can get the current URL and store it in a variable, do print via cy.log()
context('Get Current URL', () => {
it('Get current url and print', () => {
cy.visit('https://docs.cypress.io/api/commands/url')
cy.url().then(url => {
const getUrl = url
cy.log('Current URL is : '+getUrl)
})
})
})
#Max thanks this helped to get some ideas on different versions.
The way I did it is:
Create a .json file in your fixtures folder (name it whatever you want).
On the new .json file, only add: { } brackets and leave the rest blank. The function will self populate that .json file.
Create a new function on the commands page to easily call it on your test.
It would probably be best to create two functions, 1 function to write url or the sliced piece of the url, and the another function to call it so you can use it.
A. Example of 1st method, this method cuts the id off of the URL and stores it on the .json file:
Cypress.Commands.add('writeToJSON', (nameOfJSONSlicedSection) =>
{
cy.url().then(urlID =>
{
let urlBit = urlID.slice(urlID.indexOf('s/') + 2, urlID.indexOf('/edit'))
cy.writeFile('cypress/fixtures/XYZ.json', {name: nameOfJSONSlicedSection, id: urlBit}) /*{ }<-- these will populate the json file with name: xxxxx and id:xxxxx, you can changes those to whatever meets your requirements. using .slice() to take a section of the url. I needed the id that is on the url, so I cut only that section out and put it on the json file.*/
})
})
B. 2nd example function of calling it to be used.
This function is to type in the id that is on the url into a search box, to find the item I require on a different it() block.
Cypress.Commands.add('readJSONFile', (storedJSONFile) =>
{
cy.readFile('cypress/fixtures/XYZ.json').its('id').then((urlSetter) => {
cy.log(storedJSONFile, 'returning ID: ' + urlSetter)
//Search for Story
cy.get('Search text box').should('be.visible').type(urlSetter, {delay: 75})
})
})
/*here I use a .then() and hold the "id" with "urlSetter", then I type it in the search box to find it by the id that is in the URL. Also note that using ".its()" you can call any part section you require, example: .its('name') or .its('id') */
I hope this helps!

Force jQuery.load() to POST when using jQuery.param()

Ok, so .load() uses...
The POST method is used if data is
provided as an object; otherwise, GET
is assumed.
I have the following...
// an array of itemIds
var items = $selected.map(function() {
return $(this).find('.item').text();
}).get();
// post the data
$container.load(
_url,
$.param(data, true),
function(response, status, xhr) {
//...
}
);
The problem I have is that if I use $.param to serialise the data, it seems that GET is used.
If I don't use $.param then POST is used but I run into the problem again with the array not being serialised correctly and I don't receive the data in my controller.
Is there an easy way around this?
You can use jQuery.get() instead of .load():
$.get(_url, $.param(data, true), function(data) {
$container.html(data);
});
This will have the same effect as a call to load with parameters, but with a GET request instead of a POST request.

Resources