#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define all(x) begin(x), end(x)
#define len(x) int((x).size())
template <class T>
inline bool chmin(T &a, const T &b) {
if (b < a) {
a = b;
return true;
} else {
return false;
}
}
template <class T>
inline bool chmax(T &a, const T &b) {
if (a < b) {
a = b;
return true;
} else {
return false;
}
}
constexpr int Mod = 1e9 + 7;
inline int Red(int x) { return x - (x >= Mod) * Mod; }
inline void Add(int &x, int y) { x = Red(x + y); }
inline int Norm(int x) { return x + (x < 0) * Mod; }
inline void Sub(int &x, int y) { x = Norm(x - y);}
constexpr int N = 30, M = 240, S = (1 << 15) + 10;
int n, m, f[S], g[S][2], pw[M], adj[N], ee[S];
struct Edge {
int u, v, w;
bool operator<(Edge x) const { return w < x.w; }
} e[M];
#define popcnt __builtin_popcount
#define lowbit __builtin_ctz
int E(int s) {
int ans = 0;
for (int i = 0; i < m; ++i) {
auto [u, v, _] = e[i];
ans += (s >> u & 1) == 1 && (s >> v & 1) == 1;
}
return 2 * ans;
}
struct DSU {
int f[N];
void Init() { iota(all(f), 0); }
int Find(int x) {
while (x != f[x]) x = f[x] = f[f[x]];
return x;
}
bool Merge(int x, int y) {
x = Find(x), y = Find(y);
if (x == y) {
return false;
} else {
f[x] = y;
return true;
}
}
} dsu;
int GetMul() {
int mul = 1;
for (int i = 1; i <= m; ++i) mul = ll(mul) * ((Mod + 1) / 2) % Mod;
mul = ll(mul) * mul % Mod;
return mul;
}
void Dp() {
memset(adj, 0, sizeof adj);
for (int i = 0; i < m; ++i) {
auto [u, v, w] = e[i];
adj[u] += 1 << v, adj[v] += 1 << u;
}
memset(f, 0, sizeof f), memset(g, 0, sizeof g);
g[0][0] = 1;
pw[0] = 1;
for (int i = 1; i <= 2 * m; ++i) pw[i] = Red(2 * pw[i - 1]);
for (int s = 1; s < (1 << n); ++s) {
int r = lowbit(s), ss = s - (1 << r);
for (int tt = ss;; --tt &= ss) {
int t = tt + (1 << r);
Sub(g[s][1], ll(f[t]) * (g[s - t][0] + g[s - t][1]) % Mod);
Sub(g[s][0], ll(f[t]) * g[s - t][0] % Mod);
if (tt == 0) break;
}
ee[s] = E(s);
f[s] = pw[ee[s]];
for (int t = s; --t &= s;) {
int r = lowbit(s - t);
ee[t] = ee[t + (1 << r)] - popcnt(adj[r] & s);
}
for (int t = s; t > 0; --t &= s) {
Add(f[s], ll(g[t][0]) * pw[ee[s - t]] % Mod);
}
Sub(g[s][1], f[s]), Sub(g[s][0], f[s]);
}
int ans = 0;
for (int s = 1; s < (1 << n); ++s)
Sub(ans, ll(g[s][1]) * pw[ee[(1 << n) - 1 - s]] % Mod);
cout << ll(ans) * GetMul() % Mod << "\n";
}
void Proc() {
cin >> n >> m;
for (int i = 0; i < m; ++i) {
auto &[u, v, w] = e[i];
cin >> u >> v >> w, --u, --v;
}
sort(e, e + m);
if (e[m - 1].w == 1) {
Dp();
return;
}
bool is_b = true;
for (int i = 0; i < m - 1; ++i) is_b &= e[i].w < e[i + 1].w;
int mst = 0, new_m = 0;
dsu.Init();
for (int i = 0; i < m; ++i) {
auto [u, v, w] = e[i];
if (dsu.Merge(u, v)) {
mst += w;
if (is_b) e[new_m++] = e[i];
}
}
if (is_b) {
m = new_m;
Dp();
return;
}
vector<int> dmst;
for (int s = 0; s < (1 << m); ++s) {
if (popcnt(s) != n - 1) continue;
dsu.Init();
bool ok = true;
int sum = 0;
for (int i = 0; i < m; ++i) {
if ((s >> i & 1) == 0) continue;
auto [u, v, w] = e[i];
sum += w;
if (!dsu.Merge(u, v)) ok = false;
}
if (!ok || sum != mst) continue;
static vector<pair<int, int>> adj[N];
for (int i = 0; i < n; ++i) adj[i].clear();
for (int i = 0; i < m; ++i) {
auto [u, v, w] = e[i];
if ((s >> i & 1) == 1)
adj[u].emplace_back(2 * i, v), adj[v].emplace_back(2 * i + 1, u);
}
auto dfs = [&](auto dfs, int u, int p) -> int {
int s = 0;
for (auto [id, v] : adj[u]) {
if (v != p) s += (1 << id) + dfs(dfs, v, u);
}
return s;
};
for (int i = 0; i < n; ++i) dmst.push_back(dfs(dfs, i, -1));
}
int ans = 0;
for (int s = 0; s < (1 << 2 * m); ++s) {
for (int t : dmst) {
if ((s | t) == s) {
++ans;
break;
}
}
}
cout << ll(ans) * GetMul() % Mod << "\n";
}
int main() {
freopen("years.in", "r", stdin);
freopen("years.out", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin.exceptions(ios::failbit);
int _, t;
cin >> _ >> t;
for (int _ = 1; _ <= t; ++_) Proc();
}