#include <bits/stdc++.h>
using namespace std;
void start(list<int> adj[], int n, int i, set<int>& sets, stack<int>& st) {
  sets.insert(i);
  for (auto it = adj[i].begin(); it != adj[i].end(); it++) {
    if (sets.find(*it) == sets.end()) {
      start(adj, n, *it, sets, st);
    }
  }
  st.push(i);
}
vector<int> topologicalsort(list<int> adj[], int n) {
  set<int> sets;
  stack<int> sta;
  vector<int> ans;
  for (int i = 0; i < n; i++) {
    if (sets.find(i) == sets.end()) {
      start(adj, n, i, sets, sta);
    }
  }
  while (!sta.empty()) {
    ans.push_back(sta.top());
    sta.pop();
  }
  return ans;
}
int main() {
  int N;
  cin >> N;
  while (N--) {
    int n, m;
    cin >> n >> m;
    list<int> adj[n];
    int a;
    int b;
    int c;
    vector<pair<int, pair<int, int>>> vec;
    for (int i = 0; i < m; i++) {
      cin >> a >> b >> c;
      --b;
      --c;
      vec.push_back({a, {b, c}});
      if (a == 1) {
        adj[b].push_back(c);
      }
    }
    vector<int> topo = topologicalsort(adj, n);
    unordered_map<int, int> ump;
    for (int i = 0; i < topo.size(); i++) {
      ump[topo[i]] = i;
    }
    bool flag = true;
    for (int i = 0; i < vec.size(); i++) {
      a = vec[i].first;
      b = vec[i].second.first;
      c = vec[i].second.second;
      if (a == 1) {
        if (ump[b] < ump[c]) {
          continue;
        } else {
          flag = false;
          break;
        }
      } else {
        if (ump[b] < ump[c]) {
          adj[b].push_back(c);
        } else {
          adj[c].push_back(b);
        }
      }
    }
    if (flag == false) {
      cout << "NO" << endl;
    } else {
      cout << "YES" << endl;
      for (int i = 0; i < n; i++) {
        for (auto it = adj[i].begin(); it != adj[i].end(); it++) {
          cout << i + 1 << " " << *it + 1 << endl;
        }
      }
    }
  }
}
