I am trying to use an authentication state session for different test()
However Playwright is always starting a new page instance without using the authentication state "pre defined".
I tried with beforeAll and the storageState and no luck.
import { test, expect } from '#playwright/test';
import { LoginPage } from '#pageRepo/login-page';
import { envConfig } from '#data/env-config';
test.beforeAll(async ({ page }) => {
const loginStep = new LoginPage(page);
await loginStep.uiAuthentication('/', envConfig.userEmail, envConfig.userPassword);
});
test('Please work', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigateToUrl('/dashboard');
});
When I run it is visible that the login is made under beforeAll but a new instance is loaded for test('Please work')
Using the storageState instead of beforeAll the json file with the cookies configuration is created but it is never used by the test.
Anyone knows what I am doing wrong?
Make the page instance global so it can be re-used across steps (if that's what you require) e.g.
let loginPage;
// best practise to start from a clean state on each test
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.uiAuthentication('/', envConfig.userEmail, envConfig.userPassword);
});
test('Please work', async ({ page }) => {
// re-use the already created instance
await loginPage.navigateToUrl('/dashboard');
});
Show please code of your storageState.
You need to prepare the Global configuration:
https://playwright.dev/docs/test-advanced#global-setup-and-teardown
Then define global setup in playwright.config.ts
import { defineConfig } from '#playwright/test';
export default defineConfig({
**globalSetup: require.resolve('./global-setup'),**
use: {
baseURL: 'http://localhost:3000/',
**storageState: 'state.json',**
now in globalSetup you need to set authentication credationals by login + pass, or getting token by API.
Related
Right now I have React app initialized with Vite connected with Sanity.
Everything is working just fine, Sanity client is connected, React is fetching data from Sanity, I'm receiving it with no problem.
But the problem is, that if I deploy React app with Sanity connected, then I will leak my projectID and sanity_token to the fronted, which I want to avoid of course.
So I have to make some backend REST API which will be fetched by React, and then my API will fetch Sanity. I could do it with Node.js and Express without problem, but I decided that I will use NestJS and learn something instead.
But when it comes to NestJS, everything is connected a bit different.
On the front I had :
import sanityClient from '#sanity/client';
export const client = sanityClient({
projectId: import.meta.env.VITE_SANITY_PROJECT_ID,
dataset: 'production',
apiVersion: '2022-02-01',
useCdn: true,
token: import.meta.env.VITE_SANITY_TOKEN
});
And for NestJS I found something like this:
import { Injectable } from '#nestjs/common';
import sanityClient, { SanityClient } from '#sanity/client';
#Injectable()
export class SanityService {
public readonly client: SanityClient = sanityClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: 'production',
apiVersion: '2022-02-01',
useCdn: true,
token: process.env.SANITY_TOKEN
});
}
My question is that if it's a good way to connect Sanity client?
How to query Sanity client with specified GROQ query?
Till now I was using this on the frontend, but it's not gonna work in NestJS:
const query = '*[_type == "blogPost"]';
client.fetch(query)
.then((data) => {
setPosts(data);
})
.catch((err) => {
console.log(err);
})
It turned out that this is the proper way to connect with Sanity client, I had an issue with that similar to this thread
And the solution was the same as in the thread above. Add "esModuleInterop": true to tsconfig.json.
{
"compilerOptions": {
...
"esModuleInterop": true,
...
}
}
Then call for data to sanity client is working properly:
#Get()
async getAllPosts() {
// initialize sanity instance
const sanityService = new SanityService();
// your query
const query = '*[_type == "blogPost"]';
try {
const data = await sanityService.client.fetch(query);
return data;
} catch (error) {
console.log(error.msg);
}
}
and thanks for the tool 😊 .
I'm working on a Nestjs (v8.x) application relying on Passport.js with a JWT strategy through HttpOnly cookies. For testing the different endpoints of my app, I'm using supertest (v6.1.x).
In order to reach certain endpoints, I need to get an authentication cookie set after submitting credentials. When playing with the UI, everything is working correctly and I can get the data I want. However, when trying to create an automated test based on that, it does not work (at all).
My tests looks like following:
it('gives the current user when the token is valid', async () => {
const cookieToken = await authenticate(app);
const { body: user } = await request(app.getHttpServer())
.get('/users/me')
.set('Cookie', cookieToken);
expect(user.email).toEqual('joe.doe#gmail.com');
expect(user.fullname).toEqual('Joe Doe');
expect(user.uuid).toBeTruthy();
expect(user.password).toBeFalsy();
});
The authenticate function is a helper that looks like:
export const authenticate = async (
app: INestApplication,
username = 'joe.doe#gmail.com',
password = 'password',
) => {
const res = await request(app.getHttpServer()).post('/auth/login').send({
username,
password,
});
// This cookie resolves correctly
const cookieWithToken = res.headers['set-cookie'];
return cookieWithToken;
};
This tests fails and I got a 401 response from my JWT strategy. The code for this strategy looks like:
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromExtractors([
(request: Request) => {
let data = request?.cookies?.['auth-cookie'];
// In the test scenario, request.cookies is always undefined
if (!data) {
throw new UnauthorizedException();
}
return data.access_token;
},
]),
ignoreExpiration: false,
secretOrKey: jwtConstants.secret,
});
}
async validate(payload: any) {
// Not important for this issue
}
}
During the test run, request?.cookies is undefined and never set, thus throws the 401 error to the caller.
I don't know what is going but it looks like something is wrong on the way I set it.
I've tried the following approaches:
Adding withCredentials (cuz, who knows...)
Nesting the second call inside the callback resolving the login call in case there's a shared context between the requests
Relying on the same agent to make both the calls instead of directly calling superagent
But still, without success :(
Do you have any ideas?
I want to add a middleware to check the header values. if the expected do not present in the header then I want throw an error on API response. Following code is throwing error and I can see it in the console but I want to send this error to the user.
const server = new Server({
host: config.get('host'),
port: config.get('port' )
});
await server.register(require('#hapi/inert')); // eslint-disable-line #typescript-eslint/no-var-requires
server.register({
plugin: AuthService
})
server.route(
// mapping route paths with context path
routes.map((datum) => {
return {
...datum,
path: `${config.get('basePath')}${datum.path}`
};
})
);
plugin
import { notFound } from '#hapi/boom';
export const AuthService = {
name: 'authService',
version: '1.0.0',
register: async function (server: any, options: any) {
throw notFound(`Unauthorized user not found`);
}
};
Well, I think you are thinking it the express way too much. You should look at the authentication part of Hapi.
You can create a custom strategy and return an error if the header is not present.
Also, you can check how to use a Joi.schema() for all your routes.
I am currently trying to allow users to login to my Vue.js application via Twitter authentication. This is essentially the code I am using. Every time I click the Twitter sign in button I get this issue:
A cookie associated with a cross-site resource at http://google.com/ was set without the SameSite attribute. A future release of Chrome will only deliver cookies with cross-site requests if they are set with SameSite=None and Secure. You can review cookies in developer tools under Application>Storage>Cookies and see more details at https://www.chromestatus.com/feature/5088147346030592 and https://www.chromestatus.com/feature/5633521622188032.
Any idea as to how I can resolve this? Any help would be greatly appreciated. I feel like these two pieces of code could be the issue but I am not so sure.
store.js
import Vue from 'vue'
import Vuex from 'vuex'
import * as firebase from 'firebase/app'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
user: null
},
getters: {
user (state) {
return state.user
}
},
mutations: {
SET_USER (state, payload) {
state.user = payload
},
LOGOUT (state, payload) {
state.user = null
}
},
actions: {
autoSignIn({ commit }, payload) {
const newUser = {
userDetails: payload.providerData
}
commit('SET_USER', newUser)
},
signIn({ commit }) {
var provider = new firebase.auth.TwitterAuthProvider();
firebase.auth().signInWithRedirect(provider);
firebase.auth().getRedirectResult().then(result => {
// The signed-in user info.
var user = result.user;
commit('SET_USER', user)
}).catch(error => {
alert(error)
return
})
},
logout({ commit }) {
firebase.auth().signOut().then(function () {
commit('LOGOUT')
}).catch(function (error) {
alert(error)
return
});
}
}
})
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import {store} from './vuex/store'
import * as firebase from 'firebase/app'
import Vuex from 'vuex'
import {config} from './firebaseConfig'
// Firebase App (the core Firebase SDK) is always required and must be listed first
// If you enabled Analytics in your project, add the Firebase SDK for Analytics
import "firebase/analytics"
// Add the Firebase products that you want to use
import "firebase/auth"
import "firebase/firestore"
Vue.use(Vuex)
Vue.config.productionTip = false
/* eslint-disable no-new */
firebase.initializeApp(config)
const check = firebase.auth().onAuthStateChanged((user) => {
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>',
store,
created() {
if (user) {
store.dispatch('autoSignIn', user)
}
}
})
check()
})
This warning is coming from a google.com cookie, so it's not something you can affect. You can get more on the context of these changes over on https://web.dev/samesite-cookies-explained however there's no action you need to take. If there are any warnings associated with your domain, then you should check to see if there's an appropriate SameSite value to set on your cookie.
To explain what's happening here, even though you are using Twitter Sign-In, you probably have some kind of Google supplied third-party resource on your site. This may be retrieving the Firebase libraries, Google Analytics, or perhaps you're loading the Google Sign-In library in there too. As you have some eligible cookies in your browser, they are also being sent on these requests. They do not have a SameSite attribute added, so as a result once the SameSite=Lax by default enforcement is in place then these cookies will no longer be sent.
A good way to test this is to open up a new incognito session so you can be sure you only have new cookies set and then see if you still get the warning, it may simply be you have some older cookies in your current profile. However, the warning is just that - a warning, not an error. For compatibility with older browsers, sites and services may continue to set certain cookies without the SameSite attribute.
I had the wrong callback url in my Twitter app. Didn't realise firebase gave you a callback URL once you insert the API/secret API key in firebase.
I am creating a GraphQL app using Next.js for server side rendering. As you might know, there is a recommended way to implement clean URL using Express. I am trying to achieve the same using graphql-yoga but it's not working.
I have tried server.express.get('/route', ...) and server.get('/route', ...) but nothing is working. In the documentation they have given server.express.get(server.options.endpoint, handler()) but it's not working for me.
Has anyone ever implemented clean Next.js URL in a GraphQL Yoga server, and how did you achieve it? Below is how I am creating the server.
function createServer() {
return new GraphQLServer({
typeDefs: "src/schema.graphql",
resolvers: {
Mutation,
Query
},
context: req => ({ ...req, db })
});
}
const server = createServer();
server.express.post('/product/name', (req,res,next) => {
//this is where i want to implement next clean url
//but it's not working
console.log('Am never reached..');
next();
})
With the new versions of Next.js, creating clean URL is straightforward.
Create a parameterised page (e.g. pages/post/[pid].js):
import { useRouter } from 'next/router'
const Post = () => {
const router = useRouter()
const { pid } = router.query
return <p>Post: {pid}</p>
}
export default Post
More info in the Next.js documentation regarding dynamic routes.
You can then link to it and show the desired URL:
<Link href="/post/[pid]" as="/post/abc">
<a>First Post</a>
</Link>