I'm taking on a research project that uses expo to develop a mobile application. However, I am facing the following error expo-app-loading is deprecated in favor of SplashScreen.preventAutoHideAsync() instead. and I don't know how to solve it. I was able to map and see that this error is coming from this part of the code:
import AsyncStorage from '#react-native-async-storage/async-storage'
import DailyLog from "../../models/DailyLog";
export const FETCH_RECORD = "FETCH_RECORD";
export const FETCH_OR_CREATE_RECORD = "FETCH_OR_CREATE_RECORD";
export const FETCH_DAILY_LOGS = "FETCH_DAILY_LOGS";
export const SAVE_LOG = "SAVE_LOG";
export const SAVE_LOG_COMMIT = "SAVE_LOG_COMMIT";
export const SAVE_LOG_ROLLBACK = "SAVE_LOG_ROLLBACK";
export const UPDATE_RECORD = "UPDATE_RECORD";
export const UPDATE_RECORD_ROLLBACK = "UPDATE_RECORD_ROLLBACK";
export const LOAD_RECORD = "LOAD_RECORD";
export const LOAD_DAILY_LOGS = "LOAD_DAILY_LOGS";
import moment from "moment";
import Localhost from "../../constants/Localhost";
import Traducao from "../../components/Traducao/Traducao";
export const fetchRecord = () => {
console.log("fetchRecord")
return async (dispatch, getState) => {
const token = getState().user.token;
const userId = getState().user.currentUser.id;
const responseRecord = await fetch(
`http://${Localhost.address}${Localhost.port}/aes/webresources/secured/record/find/${userId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: `Bearer ${token}`,
},
}
);
if (!responseRecord.ok) {
throw new Error(Traducao.t("getRegistryError"));
}
//console.log("Aqui")
let record = await responseRecord.json();
//console.log(record)
dispatch({
type: FETCH_RECORD,
recordId: record.id,
dailyGoal: record.dailyGoal,
weeklyGoal: record.weeklyGoal,
userId: userId,
});
};
};
Can anyone help me? I am using expo version 6.0.1 and the project is on SDK version 45.
you should use SplashScreen.preventAutoHideAsync() instead.
The expo-app-loading package is used to display a loading screen when the app starts.so you need to update your code to use the new API.
you can use SplashScreen.preventAutoHideAsync() to prevent the splash screen from hiding automatically:
import { SplashScreen } from 'expo';
// Call this function in your component's useEffect or componentDidMount lifecycle method.
const preventAutoHide = async () => {
await SplashScreen.preventAutoHideAsync();
}
Note that you may need to import the SplashScreen module from the expo package and call preventAutoHide in your component's lifecycle method.
Also, make sure to call SplashScreen.hideAsync() when you're ready to hide the splash screen, or you can use SplashScreen.hide() if your app is using Expo SDK version >=33.0.0.
Related
I am trying to mock the init method provided by sentry-expo and so far, this is what I have come up with:
setupFilesAfterEnv.ts
import '#testing-library/jest-native/extend-expect';
import * as Sentry from 'sentry-expo';
import sentryTestkitSuite from 'sentry-testkit';
const DUMMY_DSN = 'https://acacaeaccacacacabcaacdacdacadaca#sentry.io/000001';
const { sentryTransport } = sentryTestkitSuite();
// https://stackoverflow.com/questions/44649699/service-mocked-with-jest-causes-the-module-factory-of-jest-mock-is-not-allowe
// Cannot use the imported module as a value directly
const mockSentryTransport = sentryTransport as jest.Mocked<
typeof sentryTransport
>;
jest.mock('sentry-expo', () => ({
...jest.requireActual('sentry-expo'),
init: (options?: Sentry.SentryExpoNativeOptions) => ({
...options,
transport: mockSentryTransport,
}),
}));
beforeAll(() =>
Sentry.init({
dsn: DUMMY_DSN,
release: 'test',
tracesSampleRate: 1,
beforeSend(event) {
return {
...event,
extra: { os: 'mac-os' },
};
},
}),
);
beforeEach(() => {
sentryTestkitSuite().testkit.reset();
});
All the test cases which have used Sentry to capture exceptions successfully pass.
Now, I have created a file for adding standard crash-reporting utilities:
crash-reporting.ts
import * as Sentry from 'sentry-expo';
import { getEnvironmentConfig } from '#utils/environment/environment';
const routingInstrumentation =
new Sentry.Native.ReactNavigationInstrumentation();
export const initialiseCrashReporting = () => {
return Sentry.init({
dsn: getEnvironmentConfig()?.sentryDSN,
// Enable it only when you install the Expo development build on your device/simulator
// If you enable it while running the app in Expo Go, native dependencies will not work as expected such as Sentry
enableInExpoDevelopment: __DEV__,
debug: __DEV__, // If `true`, Sentry will try to print out useful debugging information if something goes wrong with sending the event. Set it to `false` in production,
environment: getEnvironmentConfig()?.appEnv ?? 'development',
tracesSampleRate: __DEV__ ? 1 : 0.2,
integrations: [
new Sentry.Native.ReactNativeTracing({
tracingOrigins: ['localhost', /^\//],
routingInstrumentation,
}),
],
});
};
export const { wrap: sentryWrap } = Sentry.Native;
I am trying to test the above crash-reporting module like so:
crash-reporting.test.ts
import * as Sentry from 'sentry-expo';
import { initialiseCrashReporting } from './crash-reporting';
jest.mock('sentry-expo', () => {
const originalModule = jest.requireActual('sentry-expo');
return {
...originalModule,
init: jest.fn(),
};
});
describe('Crash Reporting Test Suite', () => {
it('should initialise sentry', () => {
const initSpy = jest.spyOn(Sentry, 'init');
initialiseCrashReporting();
expect(initSpy).toHaveBeenCalled();
});
});
Even though initialiseCrashReporting gets called, spyOn never catches the event where init gets called.
I realised that the globally mocked sentry-expo never gets overridden with the one in the crash-reporting.test.ts file.
I have 2 below-given questions related to this problem:
How can I override the globally mocked modules? Or how can I be assured that by calling initialiseCrashReporting, I am initialising sentry?
Can we override global beforeall for specific test cases?
Thanks in anticipation!
I am trying to pass data from the server to the client to load my app faster and prevent multiple calls to the database.
Via Fetch
SvelteKit is made to do this via the fetch function. This is great if you have an endpoint that allows for custom fetch. But what if you don't?
Firebase is a perfect example of not having a custom fetch function.
Cookies
I would think I could use cookies, but when I set the cookie, it just prints 'undefined' and never gets set.
<script lang="ts" context="module">
import Cookies from 'js-cookie';
import { browser } from '$app/env';
import { getResources } from '../modules/resource';
export async function load() {
if (browser) {
// working code would use JSON.parse
const c = Cookies.get('r');
return {
props: {
resources: c
}
};
} else {
// server
const r = await getResources();
// working code would use JSON.stringify
Cookies.set('resources', r);
// no cookies were set?
console.log(Cookies.get());
return {
props: {
resources: r
}
};
}
}
</script>
So my code loads correctly, then dissapears when the browser load function is loaded...
Surely there is a functioning way to do this?
J
So it seems the official answer by Rich Harris is to use and a rest api endpoint AND fetch.
routes/something.ts
import { getFirebaseDoc } from "../modules/posts";
export async function get() {
return {
body: await getFirebaseDoc()
};
}
routes/content.svelte
export async function load({ fetch }) {
const res = await fetch('/resources');
if (res.ok) {
return {
props: { resources: await res.json() }
};
}
return {
status: res.status,
error: new Error()
};
}
This seems extraneous and problematic as I speak of here, but it also seems like the only way.
J
You need to use a handler that injects the cookie into the server response (because load functions do not expose the request or headers to the browser, they are just used for loading props I believe). Example here: https://github.com/sveltejs/kit/blob/59358960ff2c32d714c47957a2350f459b9ccba8/packages/kit/test/apps/basics/src/hooks.js#L42
https://kit.svelte.dev/docs/hooks#handle
export async function handle({ event, resolve }) {
event.locals.user = await getUserInformation(event.request.headers.get('cookie'));
const response = await resolve(event);
response.headers.set('x-custom-header', 'potato');
response.headers.append('set-cookie', 'name=SvelteKit; path=/; HttpOnly');
return response;
}
FYI: This functionality was only added 11 days ago in #sveltejs/kit#1.0.0-next.267: https://github.com/sveltejs/kit/pull/3631
No need to use fetch!
You can get the data however you like!
<script context="module">
import db from '$/firebaseConfig'
export async function load() {
const eventref = db.ref('cats/whiskers');
const snapshot = await eventref.once('value');
const res = snapshot.val();
return { props: { myData: res.data } } // return data under `props` key will be passed to component
}
</script>
<script>
export let myData //data gets injected into your component
</script>
<pre>{JSON.stringify(myData, null, 4)}</pre>
Here's a quick demo on how to fetch data using axios, same principle applies for firebase: https://stackblitz.com/edit/sveltejs-kit-template-default-bpr1uq?file=src/routes/index.svelte
If you want to only load data on the server you should use an "endpoint" (https://kit.svelte.dev/docs/routing#endpoints)
My solution might solve it especially for those who work with (e.g: laravel_session), actually in your case if you want to retain the cookie data when loading on each endpoint.
What you should gonna do is to create an interface to pass the event on every api() call
interface ApiParams {
method: string;
event: RequestEvent<Record<string, string>>;
resource?: string;
data?: Record<string, unknown>;
}
Now we need to modify the default sveltekit api(), provide the whole event.
// localhost:3000/users
export const get: RequestHandler = async (event) => {
const response = await api({method: 'get', resource: 'users', event});
// ...
});
Inside your api() function, set your event.locals but make sure to update your app.d.ts
// app.d.ts
declare namespace App {
interface Locals {
r: string;
}
//...
}
// api.ts
export async function api(params: ApiParams) {
// ...
params.event.locals.r = response.headers.get('r')
});
Lastly, update your hooks.ts
/** #type {import('#sveltejs/kit').Handle} */
export const handle: Handle = async ({ event, resolve }) => {
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
const response = await resolve(event);
if (!cookies.whatevercookie && event.locals.r) {
response.headers.set(
'set-cookie',
cookie.serialize('whatevercookie', event.locals.r, {
path: '/',
httpOnly: true
})
);
}
return response;
});
Refer to my project:
hooks.ts
app.d.ts
_api.ts
index.ts
I'm trying to refactor my Ember acceptance tests to not use the deprecated authorize method, as it is throwing a warning:
The `authorize` method should be overridden in your application adapter
I checked the docs, and numberous other sources, but they don't actually explain how to migrate my code. Here's what I've got at the moment:
// projectname/app/pods/login/controller.js (excerpt)
export default Controller.extend({
session: service(),
sessionToken: null,
onSuccess: function(res) {
res = res.response;
this.set('sessionToken', res.session);
if (res.state === "authenticated") {
document.cookie = "token="+res.session+";path=/;";
var authOptions = {
success: true,
data : {
session : res.session,
}
};
this.get('session').authenticate("authenticator:company", authOptions);
}
}
});
And this must be the part that I'm meant to get rid of:
// project/app/adapters/application.js (excerpt)
export default DS.RESTAdapter.extend(DataAdapterMixin, {
authorize(xhr) { // This is deprecated! I should remove it
let sessionToken = this.get('session.data.authenticated.session');
if (sessionToken && !isEmpty(sessionToken)) {
xhr.setRequestHeader('Authorization', "Token " + sessionToken);
}
},
});
And here is my test:
import { test, module } from 'qunit';
import { visit, currentURL, find, click, fillIn } from '#ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import { authenticateSession} from 'ember-simple-auth/test-support';
module('moduleName', function(hooks) {
setupApplicationTest(hooks);
test('moduleName', async function(assert) {
// await authenticateSession(this.application); // Never works
// await authenticateSession(); // Never works
await authenticateSession({
authenticator: "authenticator:company"
}); // Works slightly more?
await visit('/my/other/page');
await assert.equal(currentURL(), '/my/other/page');
});
});
REMOVING the authorize method and attempting either of the commented out methods yields:
Error: Assertion Failed: The `authorize` method should be overridden in your application adapter. It should accept a single argument, the request object.
If I use the authenticator block as an arg, then regardless of the presence of the authorize method, I simply get:
actual: >
/login
expected: >
/my/other/page
Which, I assume, is because it did not login.
Leaving the authorize method there, and trying the commented methods yields:
Error: Browser timeout exceeded: 10s
Per the docs you linked above: To replace authorizers in an application, simply get the session data from the session service and inject it where needed.
Since you need the session data in your Authorization header, a possible solution for your use case may look like this:
export default DS.RESTAdapter.extend(DataAdapterMixin, {
headers: computed('session.data.authenticated.session', function() {
const headers = {};
let sessionToken = this.get('session.data.authenticated.session');
if (sessionToken && !isEmpty(sessionToken)) {
headers['Authorization'] = "Token " + sessionToken;
}
return headers;
})
});
This should allow you to dynamically set the Authorization header, without doing so via the authorize method.
Ember Simple Auth, has an excellent community and quickly created a guide on how to upgrade to v3.
The latest version fixes this problem completely - If anyone is having this problem, upgrading to 2.1.1 should allow you to use the new format in your application.js:
headers: computed('session.data.authenticated.session', function() {
let headers = {};
let sessionToken = this.get('session.data.authenticated.session');
if (sessionToken && !isEmpty(sessionToken)) {
headers['Authorization'] = "Token " + sessionToken;
}
return headers;
}),
This problem was only present in 2.1.0.
I have a service that uses a custom axios instance that I am trying to test but I keep getting an error.
Here is the error:
: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
Here is the test:
import moxios from 'moxios';
import NotificationService, { instance } from '../NotificationService';
beforeEach(() => {
moxios.install(instance);
});
afterEach(() => {
moxios.uninstall(instance);
});
const fetchNotifData = {
data: {
bell: false,
rollups: []
}
};
describe('NotificationService.js', () => {
it('returns the bell property', async done => {
const isResolved = true;
const data = await NotificationService.fetchNotifications(isResolved);
moxios.wait(() => {
let request = moxios.requests.mostRecent();
console.log(request);
request
.respondWith({
status: 200,
response: fetchNotifData
})
.then(() => {
console.log(data);
expect(data).toHaveProperty('data.bell');
done();
});
});
});
});
And here is the code that I'm trying to test:
import axios from 'axios';
// hardcoded user guid
const userId = '8c4';
// axios instance with hardcoded url and auth header
export const instance = axios.create({
baseURL: 'hidden',
headers: {
Authorization:
'JWT ey'
});
/**
* Notification Service
* Call these methods from the Notification Vuex Module
*/
export default class NotificationService {
/**
* #GET Gets a list of Notifications for a User
* #returns {AxiosPromise<any>}
* #param query
*/
static async fetchNotifications(query) {
try {
const res = await instance.get(`/rollups/user/${userId}`, {
query: query
});
console.log('NotificationService.fetchNotifications()', res);
return res;
} catch (error) {
console.error(error);
}
}
}
I've tried shortening the jest timeout and that did not work. I think it is moxios not installing the axios instance properly, but I can't find any reason why it wouldn't.
Any help is appreciated, thanks in advance.
have you tried changing the Jest environment settings by adding this to your test file?
/**
* #jest-environment node
*/
import moxios from 'moxios';
...
Jest tends to prevent the requests from going out unless you add that. Either way, I use nock instead of moxios and I recommend it.
I created an axios instance ...
// api/index.js
const api = axios.create({
baseURL: '/api/',
timeout: 2500,
headers: { Accept: 'application/json' },
});
export default api;
And severals modules use it ..
// api/versions.js
import api from './api';
export function getVersions() {
return api.get('/versions');
}
I try to test like ..
// Test
import { getVersions } from './api/versions';
const versions= [{ id: 1, desc: 'v1' }, { id: 2, desc: 'v2' }];
mockAdapter.onGet('/versions').reply(200, versions);
getVersions.then((resp) => { // resp is UNDEFINED?
expect(resp.data).toEqual(versions);
done();
});
Why resp is undefined?
Two things to try here:
Maybe you already have this elsewhere in your code, but be sure to set up mockAdaptor:
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mockAdapter = new MockAdapter(axios);
I haven't found a way to get the mock adapter working when the function you are testing uses 'axios.create' to set up a new axios instance. Try something along the lines of this instead:
// api/index.js
const api = {
get(path) {
return axios.get('/api' + path)
.then((response) => {
return response.data;
});
}
}
export default api;
For anyone still struggling with this.
You need to make sure you iniatilise your MockAdapter outside a test body.
ie.
❌ Incorrect ❌
it('should do a thing', () => {
const mockAdapter = new MockAdapter(axios);
})
✅ Correct ✅
const mockAdapter = new MockAdapter(axios);
it('should pass' () => {})
according to James M. advice, I updated my api/index.js , not using the axios.create...
api/index.js
import http from 'axios'
export default {
fetchShoppingLists: () => {
console.log('API FETCH SHOPPINGLISTS')
return http
.get('http://localhost:3000/shoppinglists')
.then(response => {
return response
})
.catch(error => {
console.log('FETCH ERROR: ', error)
})
}
}
You don't need axios-mock-adapter. Here is how I mock my axios:
// src/__mocks__/axios.ts
const mockAxios = jest.genMockFromModule('axios')
// this is the key to fix the axios.create() undefined error!
mockAxios.create = jest.fn(() => mockAxios)
export default mockAxios