web-dev-qa-db-fra.com

Comment configurer des données de test lorsque vous testez les règles de Firestore avec Emulator?

Je travaille sur des tests pour les règles de cloud Firestore, à l'aide de mocha _ et firestore émulateur , et la question est de savoir comment initialiser certaines données de test avant Tests en cours d'exécution?

Pour tester mes règles, j'ai d'abord besoin d'initialiser certaines données de test. Le problème est que je ne peux pas mettre de données dans un document lorsque vous travaillez avec émulateur , documents ont uniquement id. Je n'ai trouvé aucun exemple de configuration de données de test pour les tests de règles dans THE DOCS , j'ai donc essayé d'utiliser les deux makeDocumentSnapshot de @firebase/testing Et la création de documents via APP Créée avec initializeAdminApp.

Utilisez cas :

Pour accéder à un document à /objects/{object_id}, Un utilisateur doit être authentifié et avoir read autorisation: get('/objects/{object_id}/users/{$(request.auth.uid)}').data.read == true. De plus, object doit être disponible: get('/objects/{object_id}').data.available == true.

Donc, pour tester mes règles, j'ai besoin de quelques données de test prédéfinies avec les autorisations de l'utilisateur.

Structure de dB attendue :

objects collection:
  object_id: {
    // document fields:
    available (bool)

    // nested collection:
    users collection: {
      user_id: {
        // document fields:
        read (bool)
      }
    }
  }

Exemple de mes règles :

service cloud.firestore {
  match /databases/{database}/documents {
    match /objects/{object} {
      function objectAvailable() {
        return resource.data.available;
      }
      // User has read access.
      function userCanReadObject() {
        return get(/databases/$(database)/documents/objects/$(object)/users/$(request.auth.uid)).data.read == true;
      }
      // Objects Permission Rules
      allow read: if objectAvailable() && userCanReadObject();
      allow write: if false;

      // Access forbidden. Used for permission rules only.
      match /users/{document=**} {
        allow read, write: if false;
      }
    }
  }
}

Exemple de mes tests :

const firebase = require('@firebase/testing');
const fs = require('fs');

// Load Firestore rules from file
const firestoreRules = fs.readFileSync('../firestore.rules', 'utf8');
const projectId = 'test-application';
const test = require('firebase-functions-test')({ projectId, databaseName: projectId });

describe('Tests for Rules', () => {
  let adminApp;

  const testData = {
    myObj: {
      id: 'test',
      data: {
        available: true,
      },
    },
    alice: {
      id: 1,
      data: {
        read: true,
      },
    },
  };

  before(async () => {
    // Load Rules
    await firebase.loadFirestoreRules({ projectId,  rules: firestoreRules });

    // Initialize admin app.
    adminApp = firebase.initializeAdminApp({ projectId }).firestore();

    // Create test data
    await adminApp.doc(`objects/${testData.myObj.id}`).set(testData.myObj.data);
    await adminApp
      .doc(`objects/${testData.myObj.id}/users/${testData.alice.id}`)
      .set(testData.alice.data);

    // Create test data with  `firebase-functions-test`
    // test.firestore.makeDocumentSnapshot(testData.myObj.data, `objects/${testData.myObj.id}`);
    // test.firestore.makeDocumentSnapshot(
    //   testData.alice.data,
    //   `objects/${testData.myObj.id}/users/${testData.alice.id}`,
    // );
  });

  beforeEach(async () => {
    await firebase.clearFirestoreData({ projectId });
  });

  after(async () => {
    // Shut down all testing Firestore applications after testing is done.
    await Promise.all(firebase.apps().map(app => app.delete()));
  });

  describe('Testing', () => {
    it('User with permission can read objects data', async () => {
      const db = firebase
        .initializeTestApp({ projectId, auth: { uid: testData.alice.id } })
        .firestore();
      const testObj = db.doc(`objects/${testData.myObj.id}`);

      await firebase.assertSucceeds(testObj.get());
    });
  });
});

Sortie de la console pour le test Run:

1) User with permission can read objects data
0 passing (206ms)
1 failing
1) Tests for Rules
 Testing
   User with permission can read objects data:
FirebaseError: 
false for 'get' @ L53

Pour vérifier les données de test créées, j'ai ajouté le code suivant avant await firebase.assertSucceeds(testObj.get()); Ligne:

const o = await adminApp.doc(`objects/${testData.myObj.id}`).get();
const u = await adminApp.doc(`objects/${testData.myObj.id}/users/${testData.alice.id}`).get();
console.log('obj data: ', o.id, o.data());
console.log('user data: ', u.id, u.data());

La sortie est la suivante:

obj data:  test undefined
user data:  1 undefined

J'ai également essayé de supprimer le code de beforeEach, le résultat est le même.

8
greg0r

Vous devez ajouter des données avant d'appliquer les règles.

Informations détaillées que vous pouvez trouver ici

const firebase = require('@firebase/testing');
const fs = require('fs');
let db
let projectId = `my-project-id-${Date.now()}`

async function setup(auth) {
  const app = await firebase.initializeTestApp({
    projectId: projectId,
    auth: auth
  });

  db = app.firestore();

  let data = {
    'users/alovelace': {
      first: 'Ada',
      last: 'Lovelace'
    }
  }

  // Add data before apply rules
  for (const key in data) {
    const ref = db.doc(key);
    await ref.set(data[key]);
  }

  // Apply rules
  await firebase.loadFirestoreRules({
    projectId,
    rules: fs.readFileSync('firestore.rules', 'utf8')
  });
}

test('logged in', async () => {
  await setup({ uid: "alovelace" })

  let docRef = db.collection('users');

  // check if there is data
  let users = await docRef.get()
  users.forEach(user => {
  console.warn(user.id, user.data())
  });

  let read = await firebase.assertSucceeds(docRef.get());
  let write = await firebase.assertFails(docRef.add({}));

  await expect(read)
  await expect(write)
});

afterAll(async () => {
  Promise.all(firebase.apps().map(app => app.delete()))
});

firestore.Rules

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
       allow read:if request.auth.uid != null;
       allow write: if false
    }
  }
}
1
Yoruba